diff --git a/CMakeLists.txt b/CMakeLists.txt
index 561da3595..fa2531670 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -351,6 +351,7 @@ option(Z3_BUILD_LIBZ3_SHARED "Build libz3 as a shared library if true, otherwise
################################################################################
if (NOT MSVC)
z3_add_cxx_flag("-fvisibility=hidden" REQUIRED)
+ z3_add_cxx_flag("-fvisibility-inlines-hidden" REQUIRED)
endif()
################################################################################
diff --git a/README.md b/README.md
index bbbe2e361..f9fad4f46 100644
--- a/README.md
+++ b/README.md
@@ -14,9 +14,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z
## Build status
-| Azure Pipelines | TravisCI |
-| --------------- | -------- |
-[](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [](https://travis-ci.org/Z3Prover/z3)
+| Azure Pipelines |
+| --------------- |
+[](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master)
[1]: #building-z3-on-windows-using-visual-studio-command-prompt
[2]: #building-z3-using-make-and-gccclang
@@ -44,6 +44,8 @@ cd build
nmake
```
+Z3 uses C++17. The recommended version of Visual Studio is therefore VS2019.
+
## Building Z3 using make and GCC/Clang
Execute:
diff --git a/.travis.yml b/contrib/.travis.yml
similarity index 100%
rename from .travis.yml
rename to contrib/.travis.yml
diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml
index 9e6ab531c..bd96889a3 100644
--- a/scripts/build-win-signed.yml
+++ b/scripts/build-win-signed.yml
@@ -25,7 +25,7 @@ jobs:
- task: EsrpCodeSigning@1
displayName: Sign
inputs:
- ConnectedServiceName: 'z3-esrp-signing'
+ ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin'
Pattern: 'Microsoft.Z3.dll,libz3.dll,libz3java.dll,z3.exe'
signConfigType: 'inlineSignParams'
diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py
deleted file mode 100644
index d872645a6..000000000
--- a/scripts/mk_nuget_release.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#
-# Copyright (c) 2018 Microsoft Corporation
-#
-
-# 1. download releases from github
-# 2. copy over libz3.dll for the different architectures
-# 3. copy over Microsoft.Z3.dll from suitable distribution
-# 4. copy nuspec file from packages
-# 5. call nuget pack
-# 6. sign package
-
-import json
-import os
-import urllib.request
-import zipfile
-import sys
-import os.path
-import shutil
-import subprocess
-import mk_util
-import mk_project
-
-release_data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/releases/latest").read().decode())
-release_tag_name = release_data['tag_name']
-release_tag_ref_data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/git/refs/tags/%s" % release_tag_name).read().decode())
-release_tag_sha = release_tag_ref_data['object']['sha']
-#release_tag_data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/commits/%s" % release_tag_sha).read().decode())
-
-release_version = release_tag_name[3:]
-release_commit = release_tag_sha # release_tag_data['object']['sha']
-
-print(release_version)
-
-def mk_dir(d):
- if not os.path.exists(d):
- os.makedirs(d)
-
-def download_installs():
- for asset in release_data['assets']:
- url = asset['browser_download_url']
- name = asset['name']
- print("Downloading ", url)
- sys.stdout.flush()
- urllib.request.urlretrieve(url, "packages/%s" % name)
-
-os_info = {"z64-ubuntu-14" : ('so', 'ubuntu.14.04-x64'),
- 'ubuntu-16' : ('so', 'ubuntu-x64'),
- 'x64-win' : ('dll', 'win-x64'),
-# Skip x86 as I can't get dotnet build to produce AnyCPU TargetPlatform
-# 'x86-win' : ('dll', 'win-x86'),
- 'osx' : ('dylib', 'osx-x64'),
- 'debian' : ('so', 'debian.8-x64') }
-
-def classify_package(f):
- for os_name in os_info:
- if os_name in f:
- ext, dst = os_info[os_name]
- return os_name, f[:-4], ext, dst
- return None
-
-
-def unpack():
- shutil.rmtree("out", ignore_errors=True)
- # unzip files in packages
- # out
- # +- runtimes
- # +- win-x64
- # +- win-x86
- # +- ubuntu.16.04-x64
- # +- ubuntu.14.04-x64
- # +- debian.8-x64
- # +- osx-x64
- # +
- for f in os.listdir("packages"):
- print(f)
- if f.endswith(".zip") and classify_package(f):
- os_name, package_dir, ext, dst = classify_package(f)
- path = os.path.abspath(os.path.join("packages", f))
- zip_ref = zipfile.ZipFile(path, 'r')
- zip_ref.extract("%s/bin/libz3.%s" % (package_dir, ext), "tmp")
- mk_dir("out/runtimes/%s/native" % dst)
- shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/native/." % dst, "/y")
- if "x64-win" in f:
- mk_dir("out/lib/netstandard1.4/")
- for b in ["Microsoft.Z3.dll"]:
- zip_ref.extract("%s/bin/%s" % (package_dir, b), "tmp")
- shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.4/%s" % b)
-
-def mk_targets():
- mk_dir("out/build")
- shutil.copy("../src/api/dotnet/Microsoft.Z3.targets.in", "out/build/Microsoft.Z3.targets")
-
-def create_nuget_spec():
- contents = """
-
-
- Microsoft.Z3
- {0}
- Microsoft
-
-Z3 is a satisfiability modulo theories solver from Microsoft Research.
-
-Linux Dependencies:
- libgomp.so.1 installed
-
- © Microsoft Corporation. All rights reserved.
- smt constraint solver theorem prover
- https://raw.githubusercontent.com/Z3Prover/z3/{1}/resources/icon.jpg
- https://github.com/Z3Prover/z3
- https://raw.githubusercontent.com/Z3Prover/z3/{1}/LICENSE.txt
-
- true
- en
-
- """.format(release_version, release_commit)
-
- with open("out/Microsoft.Z3.nuspec", 'w') as f:
- f.write(contents)
-
-def create_nuget_package():
- subprocess.call(["nuget", "pack"], cwd="out")
-
-def main():
- mk_dir("packages")
- download_installs()
- unpack()
- mk_targets()
- create_nuget_spec()
- create_nuget_package()
-
-main()
diff --git a/scripts/mk_nuget_task.py b/scripts/mk_nuget_task.py
index dcb1a358b..69b67abc9 100644
--- a/scripts/mk_nuget_task.py
+++ b/scripts/mk_nuget_task.py
@@ -22,14 +22,14 @@ def mk_dir(d):
os.makedirs(d)
-os_info = {"z64-ubuntu-14" : ('so', 'ubuntu.14.04-x64'),
- 'ubuntu-18' : ('so', 'ubuntu-x64'),
- 'ubuntu-20' : ('so', 'ubuntu-x64'),
- 'glibc-2.31' : ('so', 'ubuntu-x64'),
+os_info = {"z64-ubuntu-14" : ('so', 'linux-x64'),
+ 'ubuntu-18' : ('so', 'linux-x64'),
+ 'ubuntu-20' : ('so', 'linux-x64'),
+ 'glibc-2.31' : ('so', 'linux-x64'),
'x64-win' : ('dll', 'win-x64'),
'x86-win' : ('dll', 'win-x86'),
'osx' : ('dylib', 'osx-x64'),
- 'debian' : ('so', 'debian.8-x64') }
+ 'debian' : ('so', 'linux-x64') }
def classify_package(f):
for os_name in os_info:
@@ -51,7 +51,7 @@ def unpack(packages, symbols):
# +- runtimes
# +- win-x64
# +- win-x86
- # +- ubuntu-x64
+ # +- linux-x64
# +- osx-x64
# +
tmp = "tmp" if not symbols else "tmpsym"
diff --git a/scripts/mk_util.py b/scripts/mk_util.py
index ea1ad6050..2c584ffba 100644
--- a/scripts/mk_util.py
+++ b/scripts/mk_util.py
@@ -2398,6 +2398,7 @@ def mk_config():
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
if IS_WINDOWS:
+ CXXFLAGS = '/nologo /Zi /D WIN32 /D _WINDOWS /EHsc /GS /Gd /std:c++17'
config.write(
'CC=cl\n'
'CXX=cl\n'
@@ -2438,7 +2439,7 @@ def mk_config():
'SLINK_FLAGS=/nologo /LDd\n' % static_opt)
if VS_X64:
config.write(
- 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /Gd %s %s\n' % (extra_opt, static_opt))
+ 'CXXFLAGS=/c %s /W3 /WX- /Od /Oy- /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /Gm- /RTC1 %s %s\n' % (CXXFLAGS, extra_opt, static_opt))
config.write(
'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt))
@@ -2447,7 +2448,7 @@ def mk_config():
exit(1)
else:
config.write(
- 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /Gd /arch:SSE2 %s %s\n' % (extra_opt, static_opt))
+ 'CXXFLAGS=/c %s /W3 /WX- /Od /Oy- /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /Gm- /RTC1 /arch:SSE2 %s %s\n' % (CXXFLAGS, extra_opt, static_opt))
config.write(
'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt))
@@ -2463,7 +2464,7 @@ def mk_config():
extra_opt = '%s /D _TRACE ' % extra_opt
if VS_X64:
config.write(
- 'CXXFLAGS=/c%s /Zi /nologo /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _LIB /D _WINDOWS /D _UNICODE /D UNICODE /Gm- /EHsc /GS /Gd /GF /Gy /TP %s %s\n' % (GL, extra_opt, static_opt))
+ 'CXXFLAGS=/c%s %s /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D NDEBUG /D _LIB /D UNICODE /Gm- /GF /Gy /TP %s %s\n' % (GL, CXXFLAGS, extra_opt, static_opt))
config.write(
'LINK_EXTRA_FLAGS=/link%s /profile /MACHINE:X64 /SUBSYSTEM:CONSOLE /STACK:8388608 %s\n'
'SLINK_EXTRA_FLAGS=/link%s /profile /MACHINE:X64 /SUBSYSTEM:WINDOWS /STACK:8388608 %s\n' % (LTCG, link_extra_opt, LTCG, link_extra_opt))
@@ -2472,7 +2473,7 @@ def mk_config():
exit(1)
else:
config.write(
- 'CXXFLAGS=/nologo /c%s /Zi /W3 /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _CONSOLE /D _WINDOWS /D ASYNC_COMMANDS /Gm- /EHsc /GS /Gd /arch:SSE2 %s %s\n' % (GL, extra_opt, static_opt))
+ 'CXXFLAGS=/c%s %s /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D NDEBUG /D _CONSOLE /D ASYNC_COMMANDS /Gm- /arch:SSE2 %s %s\n' % (GL, CXXFLAGS, extra_opt, static_opt))
config.write(
'LINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
'SLINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (LTCG, link_extra_opt, LTCG, maybe_disable_dynamic_base, link_extra_opt))
@@ -2514,7 +2515,7 @@ def mk_config():
if GIT_HASH:
CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
CXXFLAGS = '%s -std=c++17' % CXXFLAGS
- CXXFLAGS = '%s -fvisibility=hidden -c' % CXXFLAGS
+ CXXFLAGS = '%s -fvisibility=hidden -fvisibility-inlines-hidden -c' % CXXFLAGS
FPMATH = test_fpmath(CXX)
CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS)
if LOG_SYNC:
diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py
index bd3de3087..8f00b2755 100644
--- a/scripts/mk_win_dist.py
+++ b/scripts/mk_win_dist.py
@@ -181,10 +181,10 @@ def exec_cmds(cmds):
def mk_z3(x64):
cmds = []
if x64:
- cmds.append('call "%VCINSTALLDIR%vcvarsall.bat" amd64')
+ cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" amd64')
cmds.append('cd %s' % BUILD_X64_DIR)
else:
- cmds.append('call "%VCINSTALLDIR%vcvarsall.bat" x86')
+ cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" x86')
cmds.append('cd %s' % BUILD_X86_DIR)
cmds.append('nmake')
if exec_cmds(cmds) != 0:
diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml
index d4c72a65f..5b7a15aa3 100644
--- a/scripts/nightly.yaml
+++ b/scripts/nightly.yaml
@@ -93,7 +93,7 @@ stages:
- task: CmdLine@2
inputs:
script:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 &&
+ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 &
python scripts\mk_win_dist.py
--x86-only
--dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk
@@ -116,7 +116,7 @@ stages:
- task: CmdLine@2
inputs:
script:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 &&
+ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 &
python scripts\mk_win_dist.py
--x64-only
--dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk
diff --git a/scripts/release.yml b/scripts/release.yml
index 628563e5e..1e93d51c3 100644
--- a/scripts/release.yml
+++ b/scripts/release.yml
@@ -254,7 +254,7 @@ stages:
artifact: 'WindowsBuild-x64'
path: $(Agent.TempDirectory)
- script: cd $(Agent.TempDirectory); mkdir osx-bin; cd osx-bin; unzip ../*osx*.zip
- - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*centos*.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
- script: python3 -m pip install --user -U setuptools wheel
diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp
index cd877986d..a5b2630c7 100644
--- a/src/ackermannization/ackr_model_converter.cpp
+++ b/src/ackermannization/ackr_model_converter.cpp
@@ -66,7 +66,10 @@ public:
}
void display(std::ostream & out) override {
- out << "(ackr-model-converter)\n";
+ out << "(ackr-model-converter";
+ if (abstr_model)
+ out << *abstr_model;
+ out << ")\n";
}
protected:
@@ -102,16 +105,13 @@ void ackr_model_converter::convert_constants(model * source, model * destination
func_decl * const c = source->get_constant(i);
app * const term = info->find_term(c);
expr * value = source->get_const_interp(c);
- TRACE("ackermannize", tout << mk_ismt2_pp(c, m) << " " << term << "\n";);
- if (!term) {
+ TRACE("ackermannize", tout << mk_ismt2_pp(c, m) << " " << mk_ismt2_pp(term, m) << "\n";);
+ if (!term)
destination->register_decl(c, value);
- }
- else if (autil.is_select(term)) {
+ else if (autil.is_select(term))
add_entry(evaluator, term, value, array_interpretations);
- }
- else {
+ else
add_entry(evaluator, term, value, interpretations);
- }
}
for (auto & kv : interpretations) {
diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp
index 3a310cc34..887f1d519 100644
--- a/src/ackermannization/lackr.cpp
+++ b/src/ackermannization/lackr.cpp
@@ -295,6 +295,8 @@ bool lackr::collect_terms() {
}
if (m_autil.is_as_array(curr, f))
m_non_funs.mark(f, true);
+ if (m_autil.is_map(curr))
+ m_non_funs.mark(m_autil.get_map_func_decl(curr), true);
break;
}
case AST_QUANTIFIER:
diff --git a/src/api/api_polynomial.h b/src/api/api_polynomial.h
index 033d46211..0dbcdd4e3 100644
--- a/src/api/api_polynomial.h
+++ b/src/api/api_polynomial.h
@@ -28,9 +28,7 @@ namespace api {
// TODO: add support for caching expressions -> polynomial and back
public:
pmanager(reslimit& lim) : m_pm(lim, m_nm) {}
- ~pmanager() {}
polynomial::manager & pm() { return m_pm; }
};
-};
-
+}
diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py
index 3044760ba..fe711d4f0 100644
--- a/src/api/python/z3/z3.py
+++ b/src/api/python/z3/z3.py
@@ -6,12 +6,17 @@
# Author: Leonardo de Moura (leonardo)
############################################
-"""Z3 is a high performance theorem prover developed at Microsoft Research. Z3 is used in many applications such as: software/hardware verification and testing, constraint solving, analysis of hybrid systems, security, biology (in silico analysis), and geometrical problems.
+"""Z3 is a high performance theorem prover developed at Microsoft Research.
+
+Z3 is used in many applications such as: software/hardware verification and testing,
+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.
+Please send feedback, comments and/or corrections on the Issue tracker for
+https://github.com/Z3prover/z3.git. Your comments are very valuable.
Small example:
@@ -50,66 +55,77 @@ import sys
import io
import math
import copy
-if sys.version < '3':
- pass
-else:
+if sys.version_info.major >= 3:
from typing import Iterable
Z3_DEBUG = __debug__
+
def z3_debug():
global Z3_DEBUG
return Z3_DEBUG
-if sys.version < '3':
+
+if sys.version_info.major < 3:
def _is_int(v):
return isinstance(v, (int, long))
else:
def _is_int(v):
return isinstance(v, int)
+
def enable_trace(msg):
Z3_enable_trace(msg)
+
def disable_trace(msg):
Z3_disable_trace(msg)
+
def get_version_string():
- major = ctypes.c_uint(0)
- minor = ctypes.c_uint(0)
- build = ctypes.c_uint(0)
- rev = ctypes.c_uint(0)
- Z3_get_version(major, minor, build, rev)
- return "%s.%s.%s" % (major.value, minor.value, build.value)
+ major = ctypes.c_uint(0)
+ minor = ctypes.c_uint(0)
+ build = ctypes.c_uint(0)
+ rev = ctypes.c_uint(0)
+ Z3_get_version(major, minor, build, rev)
+ return "%s.%s.%s" % (major.value, minor.value, build.value)
+
def get_version():
- major = ctypes.c_uint(0)
- minor = ctypes.c_uint(0)
- build = ctypes.c_uint(0)
- rev = ctypes.c_uint(0)
- Z3_get_version(major, minor, build, rev)
- return (major.value, minor.value, build.value, rev.value)
+ major = ctypes.c_uint(0)
+ minor = ctypes.c_uint(0)
+ build = ctypes.c_uint(0)
+ rev = ctypes.c_uint(0)
+ Z3_get_version(major, minor, build, rev)
+ return (major.value, minor.value, build.value, rev.value)
+
def get_full_version():
- return Z3_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:
raise Z3Exception(msg)
+
def _z3_check_cint_overflow(n, name):
_z3_assert(ctypes.c_int(n).value == n, name + " is too large")
+
def open_log(fname):
"""Log interaction to a file. This function must be invoked immediately after init(). """
Z3_open_log(fname)
+
def append_log(s):
"""Append user-defined string to interaction log. """
Z3_append_log(s)
+
def to_symbol(s, ctx=None):
"""Convert an integer or string into a Z3 symbol."""
if _is_int(s):
@@ -117,6 +133,7 @@ def to_symbol(s, ctx=None):
else:
return Z3_mk_string_symbol(_get_ctx(ctx).ref(), s)
+
def _symbol2py(ctx, s):
"""Convert a Z3 symbol back into a Python object. """
if Z3_get_symbol_kind(ctx.ref(), s) == Z3_INT_SYMBOL:
@@ -127,41 +144,44 @@ def _symbol2py(ctx, s):
# Hack for having nary functions that can receive one argument that is the
# list of arguments.
# Use this when function takes a single list of arguments
+
+
def _get_args(args):
- try:
- if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
+ try:
+ if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
return args[0]
- elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)):
+ elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)):
return [arg for arg in args[0]]
- else:
+ else:
return args
- except: # len is not necessarily defined when args is not a sequence (use reflection?)
+ except TypeError: # len is not necessarily defined when args is not a sequence (use reflection?)
return args
# Use this when function takes multiple arguments
+
+
def _get_args_ast_list(args):
try:
- if isinstance(args, set) or isinstance(args, AstVector) or isinstance(args, tuple):
+ if isinstance(args, (set, AstVector, tuple)):
return [arg for arg in args]
else:
return args
- except:
+ except Exception:
return args
+
def _to_param_value(val):
if isinstance(val, bool):
- if val == True:
- return "true"
- else:
- return "false"
- else:
- return str(val)
+ return "true" if val else "false"
+ return str(val)
+
def z3_error_handler(c, e):
# Do nothing error handler, just avoid exit(0)
# The wrappers in z3core.py will raise a Z3Exception if an error is detected
return
+
class Context:
"""A Context manages all other Z3 objects, global configuration options, etc.
@@ -173,6 +193,7 @@ class Context:
computation.
The initialization method receives global configuration options for the new context.
"""
+
def __init__(self, *args, **kws):
if z3_debug():
_z3_assert(len(args) % 2 == 0, "Argument list must have an even number of elements.")
@@ -212,6 +233,8 @@ class Context:
# Global Z3 context
_main_ctx = None
+
+
def main_ctx():
"""Return a reference to the global Z3 context.
@@ -232,15 +255,18 @@ def main_ctx():
_main_ctx = Context()
return _main_ctx
+
def _get_ctx(ctx):
if ctx is None:
return main_ctx()
else:
return ctx
+
def get_ctx(ctx):
return _get_ctx(ctx)
+
def set_param(*args, **kws):
"""Set Z3 global (or module) parameters.
@@ -264,16 +290,19 @@ def set_param(*args, **kws):
Z3_global_param_set(str(prev), _to_param_value(a))
prev = None
+
def reset_params():
"""Reset all global (or module) parameters.
"""
Z3_global_param_reset_all()
+
def set_option(*args, **kws):
"""Alias for 'set_param' for backward compatibility.
"""
return set_param(*args, **kws)
+
def get_param(name):
"""Return the value of a Z3 global (or module) parameter
@@ -293,8 +322,11 @@ def get_param(name):
#########################################
# Mark objects that use pretty printer
+
+
class Z3PPObject:
"""Superclass for all Z3 objects that have support for pretty printing."""
+
def use_pp(self):
return True
@@ -308,15 +340,16 @@ class Z3PPObject:
class AstRef(Z3PPObject):
"""AST are Direct Acyclic Graphs (DAGs) used to represent sorts, declarations and expressions."""
+
def __init__(self, ast, ctx=None):
- self.ast = ast
- self.ctx = _get_ctx(ctx)
+ self.ast = ast
+ self.ctx = _get_ctx(ctx)
Z3_inc_ref(self.ctx.ref(), self.as_ast())
def __del__(self):
if self.ctx.ref() is not None and self.ast is not None:
- Z3_dec_ref(self.ctx.ref(), self.as_ast())
- self.ast = None
+ Z3_dec_ref(self.ctx.ref(), self.as_ast())
+ self.ast = None
def __deepcopy__(self, memo={}):
return _to_ast_ref(self.ast, self.ctx)
@@ -342,7 +375,7 @@ class AstRef(Z3PPObject):
elif is_false(self):
return False
elif is_eq(self) and self.num_args() == 2:
- return self.arg(0).eq(self.arg(1))
+ return self.arg(0).eq(self.arg(1))
else:
raise Z3Exception("Symbolic expressions cannot be cast to concrete Boolean values.")
@@ -413,6 +446,7 @@ class AstRef(Z3PPObject):
"""
return Z3_get_ast_hash(self.ctx_ref(), self.as_ast())
+
def is_ast(a):
"""Return `True` if `a` is an AST node.
@@ -433,6 +467,7 @@ def is_ast(a):
"""
return isinstance(a, AstRef)
+
def eq(a, b):
"""Return `True` if `a` and `b` are structurally identical AST nodes.
@@ -451,11 +486,13 @@ def eq(a, b):
_z3_assert(is_ast(a) and is_ast(b), "Z3 ASTs expected")
return a.eq(b)
+
def _ast_kind(ctx, a):
if is_ast(a):
a = a.as_ast()
return Z3_get_ast_kind(ctx.ref(), a)
+
def _ctx_from_ast_arg_list(args, default_ctx=None):
ctx = None
for a in args:
@@ -469,9 +506,11 @@ def _ctx_from_ast_arg_list(args, default_ctx=None):
ctx = default_ctx
return ctx
+
def _ctx_from_ast_args(*args):
return _ctx_from_ast_arg_list(args)
+
def _to_func_decl_array(args):
sz = len(args)
_args = (FuncDecl * sz)()
@@ -479,6 +518,7 @@ def _to_func_decl_array(args):
_args[i] = args[i].as_func_decl()
return _args, sz
+
def _to_ast_array(args):
sz = len(args)
_args = (Ast * sz)()
@@ -486,6 +526,7 @@ def _to_ast_array(args):
_args[i] = args[i].as_ast()
return _args, sz
+
def _to_ref_array(ref, args):
sz = len(args)
_args = (ref * sz)()
@@ -493,6 +534,7 @@ def _to_ref_array(ref, args):
_args[i] = args[i].as_ast()
return _args, sz
+
def _to_ast_ref(a, ctx):
k = _ast_kind(ctx, a)
if k == Z3_SORT_AST:
@@ -512,8 +554,10 @@ def _to_ast_ref(a, ctx):
def _sort_kind(ctx, s):
return Z3_get_sort_kind(ctx.ref(), s)
+
class SortRef(AstRef):
"""A Sort is essentially a type. Every Z3 expression has a sort. A sort is an AST node."""
+
def as_ast(self):
return Z3_sort_to_ast(self.ctx_ref(), self.ast)
@@ -521,7 +565,8 @@ class SortRef(AstRef):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def kind(self):
- """Return the Z3 internal kind of a sort. This method can be used to test if `self` is one of the Z3 builtin sorts.
+ """Return the Z3 internal kind of a sort.
+ This method can be used to test if `self` is one of the Z3 builtin sorts.
>>> b = BoolSort()
>>> b.kind() == Z3_BOOL_SORT
@@ -597,6 +642,7 @@ class SortRef(AstRef):
""" Hash code. """
return AstRef.__hash__(self)
+
def is_sort(s):
"""Return `True` if `s` is a Z3 sort.
@@ -609,6 +655,7 @@ def is_sort(s):
"""
return isinstance(s, SortRef)
+
def _to_sort_ref(s, ctx):
if z3_debug():
_z3_assert(isinstance(s, Sort), "Z3 Sort expected")
@@ -635,9 +682,11 @@ def _to_sort_ref(s, ctx):
return SeqSortRef(s, ctx)
return SortRef(s, ctx)
+
def _sort(ctx, a):
return _to_sort_ref(Z3_get_sort(ctx.ref(), a), ctx)
+
def DeclareSort(name, ctx=None):
"""Create a new uninterpreted sort named `name`.
@@ -662,6 +711,7 @@ def DeclareSort(name, ctx=None):
#
#########################################
+
class FuncDeclRef(AstRef):
"""Function declaration. Every constant and function have an associated declaration.
@@ -669,6 +719,7 @@ class FuncDeclRef(AstRef):
the sort (i.e., type) of each of its arguments. Note that, in Z3,
a constant is a function with 0 arguments.
"""
+
def as_ast(self):
return Z3_func_decl_to_ast(self.ctx_ref(), self.ast)
@@ -690,7 +741,8 @@ class FuncDeclRef(AstRef):
return _symbol2py(self.ctx, Z3_get_decl_name(self.ctx_ref(), self.ast))
def arity(self):
- """Return the number of arguments of a function declaration. If `self` is a constant, then `self.arity()` is 0.
+ """Return the number of arguments of a function declaration.
+ If `self` is a constant, then `self.arity()` is 0.
>>> f = Function('f', IntSort(), RealSort(), BoolSort())
>>> f.arity()
@@ -699,7 +751,8 @@ class FuncDeclRef(AstRef):
return int(Z3_get_arity(self.ctx_ref(), self.ast))
def domain(self, i):
- """Return the sort of the argument `i` of a function declaration. This method assumes that `0 <= i < self.arity()`.
+ """Return the sort of the argument `i` of a function declaration.
+ This method assumes that `0 <= i < self.arity()`.
>>> f = Function('f', IntSort(), RealSort(), BoolSort())
>>> f.domain(0)
@@ -712,7 +765,8 @@ class FuncDeclRef(AstRef):
return _to_sort_ref(Z3_get_domain(self.ctx_ref(), self.ast, i), self.ctx)
def range(self):
- """Return the sort of the range of a function declaration. For constants, this is the sort of the constant.
+ """Return the sort of the range of a function declaration.
+ For constants, this is the sort of the constant.
>>> f = Function('f', IntSort(), RealSort(), BoolSort())
>>> f.range()
@@ -721,7 +775,8 @@ class FuncDeclRef(AstRef):
return _to_sort_ref(Z3_get_range(self.ctx_ref(), self.ast), self.ctx)
def kind(self):
- """Return the internal kind of a function declaration. It can be used to identify Z3 built-in functions such as addition, multiplication, etc.
+ """Return the internal kind of a function declaration.
+ It can be used to identify Z3 built-in functions such as addition, multiplication, etc.
>>> x = Int('x')
>>> d = (x + 1).decl()
@@ -735,25 +790,25 @@ class FuncDeclRef(AstRef):
def params(self):
ctx = self.ctx
n = Z3_get_decl_num_parameters(self.ctx_ref(), self.ast)
- result = [ None for i in range(n) ]
+ result = [None for i in range(n)]
for i in range(n):
k = Z3_get_decl_parameter_kind(self.ctx_ref(), self.ast, i)
if k == Z3_PARAMETER_INT:
- result[i] = Z3_get_decl_int_parameter(self.ctx_ref(), self.ast, i)
+ result[i] = Z3_get_decl_int_parameter(self.ctx_ref(), self.ast, i)
elif k == Z3_PARAMETER_DOUBLE:
- result[i] = Z3_get_decl_double_parameter(self.ctx_ref(), self.ast, i)
+ result[i] = Z3_get_decl_double_parameter(self.ctx_ref(), self.ast, i)
elif k == Z3_PARAMETER_RATIONAL:
- result[i] = Z3_get_decl_rational_parameter(self.ctx_ref(), self.ast, i)
+ result[i] = Z3_get_decl_rational_parameter(self.ctx_ref(), self.ast, i)
elif k == Z3_PARAMETER_SYMBOL:
- result[i] = Z3_get_decl_symbol_parameter(self.ctx_ref(), self.ast, i)
+ result[i] = Z3_get_decl_symbol_parameter(self.ctx_ref(), self.ast, i)
elif k == Z3_PARAMETER_SORT:
- result[i] = SortRef(Z3_get_decl_sort_parameter(self.ctx_ref(), self.ast, i), ctx)
+ result[i] = SortRef(Z3_get_decl_sort_parameter(self.ctx_ref(), self.ast, i), ctx)
elif k == Z3_PARAMETER_AST:
- result[i] = ExprRef(Z3_get_decl_ast_parameter(self.ctx_ref(), self.ast, i), ctx)
+ result[i] = ExprRef(Z3_get_decl_ast_parameter(self.ctx_ref(), self.ast, i), ctx)
elif k == Z3_PARAMETER_FUNC_DECL:
- result[i] = FuncDeclRef(Z3_get_decl_func_decl_parameter(self.ctx_ref(), self.ast, i), ctx)
+ result[i] = FuncDeclRef(Z3_get_decl_func_decl_parameter(self.ctx_ref(), self.ast, i), ctx)
else:
- assert(False)
+ assert(False)
return result
def __call__(self, *args):
@@ -783,11 +838,12 @@ class FuncDeclRef(AstRef):
for i in range(num):
# self.domain(i).cast(args[i]) may create a new Z3 expression,
# then we must save in 'saved' to prevent it from being garbage collected.
- tmp = self.domain(i).cast(args[i])
+ tmp = self.domain(i).cast(args[i])
saved.append(tmp)
_args[i] = tmp.as_ast()
return _to_expr_ref(Z3_mk_app(self.ctx_ref(), self.ast, len(args), _args), self.ctx)
+
def is_func_decl(a):
"""Return `True` if `a` is a Z3 function declaration.
@@ -800,6 +856,7 @@ def is_func_decl(a):
"""
return isinstance(a, FuncDeclRef)
+
def Function(name, *sig):
"""Create a new Z3 uninterpreted function with the given sorts.
@@ -811,10 +868,10 @@ def Function(name, *sig):
if z3_debug():
_z3_assert(len(sig) > 0, "At least two arguments expected")
arity = len(sig) - 1
- rng = sig[arity]
+ rng = sig[arity]
if z3_debug():
_z3_assert(is_sort(rng), "Z3 sort expected")
- dom = (Sort * arity)()
+ dom = (Sort * arity)()
for i in range(arity):
if z3_debug():
_z3_assert(is_sort(sig[i]), "Z3 sort expected")
@@ -822,6 +879,7 @@ def Function(name, *sig):
ctx = rng.ctx
return FuncDeclRef(Z3_mk_func_decl(ctx.ref(), to_symbol(name, ctx), arity, dom, rng.ast), ctx)
+
def FreshFunction(*sig):
"""Create a new fresh Z3 uninterpreted function with the given sorts.
"""
@@ -838,22 +896,23 @@ def FreshFunction(*sig):
_z3_assert(is_sort(sig[i]), "Z3 sort expected")
dom[i] = sig[i].ast
ctx = rng.ctx
- return FuncDeclRef(Z3_mk_fresh_func_decl(ctx.ref(), 'f', arity, dom, rng.ast), ctx)
+ return FuncDeclRef(Z3_mk_fresh_func_decl(ctx.ref(), "f", arity, dom, rng.ast), ctx)
def _to_func_decl_ref(a, ctx):
return FuncDeclRef(a, ctx)
+
def RecFunction(name, *sig):
"""Create a new Z3 recursive with the given sorts."""
sig = _get_args(sig)
if z3_debug():
_z3_assert(len(sig) > 0, "At least two arguments expected")
arity = len(sig) - 1
- rng = sig[arity]
+ rng = sig[arity]
if z3_debug():
_z3_assert(is_sort(rng), "Z3 sort expected")
- dom = (Sort * arity)()
+ dom = (Sort * arity)()
for i in range(arity):
if z3_debug():
_z3_assert(is_sort(sig[i]), "Z3 sort expected")
@@ -861,10 +920,11 @@ def RecFunction(name, *sig):
ctx = rng.ctx
return FuncDeclRef(Z3_mk_rec_func_decl(ctx.ref(), to_symbol(name, ctx), arity, dom, rng.ast), ctx)
+
def RecAddDefinition(f, args, body):
"""Set the body of a recursive function.
Recursive definitions can be simplified if they are applied to ground
- arguments.
+ arguments.
>>> ctx = Context()
>>> fac = RecFunction('fac', IntSort(ctx), IntSort(ctx))
>>> n = Int('n', ctx)
@@ -879,7 +939,7 @@ def RecAddDefinition(f, args, body):
120
"""
if is_app(args):
- args = [args]
+ args = [args]
ctx = body.ctx
args = _get_args(args)
n = len(args)
@@ -894,6 +954,7 @@ def RecAddDefinition(f, args, body):
#
#########################################
+
class ExprRef(AstRef):
"""Constraints, formulas and terms are expressions in Z3.
@@ -904,6 +965,7 @@ class ExprRef(AstRef):
For quantifier free problems, all expressions are
function applications.
"""
+
def as_ast(self):
return self.ast
@@ -1042,6 +1104,7 @@ class ExprRef(AstRef):
else:
return []
+
def _to_expr_ref(a, ctx):
if isinstance(a, Pattern):
return PatternRef(a, ctx)
@@ -1089,6 +1152,7 @@ def _to_expr_ref(a, ctx):
return ReRef(a, ctx)
return ExprRef(a, ctx)
+
def _coerce_expr_merge(s, a):
if is_expr(a):
s1 = a.sort()
@@ -1107,6 +1171,7 @@ def _coerce_expr_merge(s, a):
else:
return s
+
def _coerce_exprs(a, b, ctx=None):
if not is_expr(a) and not is_expr(b):
a = _py2expr(a, ctx)
@@ -1123,11 +1188,12 @@ def _coerce_exprs(a, b, ctx=None):
return (a, b)
-def _reduce(f, l, a):
- r = a
- for e in l:
- r = f(r, e)
- return r
+def _reduce(func, sequence, initial):
+ result = initial
+ for element in sequence:
+ result = func(result, element)
+ return result
+
def _coerce_expr_list(alist, ctx=None):
has_expr = False
@@ -1136,9 +1202,10 @@ def _coerce_expr_list(alist, ctx=None):
has_expr = True
break
if not has_expr:
- alist = [ _py2expr(a, ctx) for a in alist ]
+ alist = [_py2expr(a, ctx) for a in alist]
s = _reduce(_coerce_expr_merge, alist, None)
- return [ s.cast(a) for a in alist ]
+ return [s.cast(a) for a in alist]
+
def is_expr(a):
"""Return `True` if `a` is a Z3 expression.
@@ -1162,6 +1229,7 @@ def is_expr(a):
"""
return isinstance(a, ExprRef)
+
def is_app(a):
"""Return `True` if `a` is a Z3 function application.
@@ -1187,6 +1255,7 @@ def is_app(a):
k = _ast_kind(a.ctx, a)
return k == Z3_NUMERAL_AST or k == Z3_APP_AST
+
def is_const(a):
"""Return `True` if `a` is Z3 constant/variable expression.
@@ -1205,6 +1274,7 @@ def is_const(a):
"""
return is_app(a) and a.num_args() == 0
+
def is_var(a):
"""Return `True` if `a` is variable.
@@ -1229,6 +1299,7 @@ def is_var(a):
"""
return is_expr(a) and _ast_kind(a.ctx, a) == Z3_VAR_AST
+
def get_var_index(a):
"""Return the de-Bruijn index of the Z3 bounded variable `a`.
@@ -1261,6 +1332,7 @@ def get_var_index(a):
_z3_assert(is_var(a), "Z3 bound variable expected")
return int(Z3_get_index_value(a.ctx.ref(), a.as_ast()))
+
def is_app_of(a, k):
"""Return `True` if `a` is an application of the given kind `k`.
@@ -1273,6 +1345,7 @@ def is_app_of(a, k):
"""
return is_app(a) and a.decl().kind() == k
+
def If(a, b, c, ctx=None):
"""Create a Z3 if-then-else expression.
@@ -1295,6 +1368,7 @@ def If(a, b, c, ctx=None):
_z3_assert(a.ctx == b.ctx, "Context mismatch")
return _to_expr_ref(Z3_mk_ite(ctx.ref(), a.as_ast(), b.as_ast(), c.as_ast()), ctx)
+
def Distinct(*args):
"""Create a Z3 distinct expression.
@@ -1310,14 +1384,15 @@ def Distinct(*args):
>>> simplify(Distinct(x, y, z), blast_distinct=True)
And(Not(x == y), Not(x == z), Not(y == z))
"""
- args = _get_args(args)
- ctx = _ctx_from_ast_arg_list(args)
+ args = _get_args(args)
+ ctx = _ctx_from_ast_arg_list(args)
if z3_debug():
_z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression")
- args = _coerce_expr_list(args, ctx)
+ args = _coerce_expr_list(args, ctx)
_args, sz = _to_ast_array(args)
return BoolRef(Z3_mk_distinct(ctx.ref(), sz, _args), ctx)
+
def _mk_bin(f, a, b):
args = (Ast * 2)()
if z3_debug():
@@ -1326,6 +1401,7 @@ def _mk_bin(f, a, b):
args[1] = b.as_ast()
return f(a.ctx.ref(), 2, args)
+
def Const(name, sort):
"""Create a constant of the given sort.
@@ -1337,6 +1413,7 @@ def Const(name, sort):
ctx = sort.ctx
return _to_expr_ref(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), sort.ast), ctx)
+
def Consts(names, sort):
"""Create several constants of the given sort.
@@ -1351,11 +1428,13 @@ def Consts(names, sort):
names = names.split(" ")
return [Const(name, sort) for name in names]
-def FreshConst(sort, prefix='c'):
+
+def FreshConst(sort, prefix="c"):
"""Create a fresh constant of a specified sort"""
ctx = _get_ctx(sort.ctx)
return _to_expr_ref(Z3_mk_fresh_const(ctx.ref(), prefix, sort.ast), ctx)
+
def Var(idx, s):
"""Create a Z3 free variable. Free variables are used to create quantified formulas.
@@ -1368,6 +1447,7 @@ def Var(idx, s):
_z3_assert(is_sort(s), "Z3 sort expected")
return _to_expr_ref(Z3_mk_bound(s.ctx_ref(), idx, s.ast), s.ctx)
+
def RealVar(idx, ctx=None):
"""
Create a real free variable. Free variables are used to create quantified formulas.
@@ -1378,6 +1458,7 @@ def RealVar(idx, ctx=None):
"""
return Var(idx, RealSort(ctx))
+
def RealVarVector(n, ctx=None):
"""
Create a list of Real free variables.
@@ -1387,7 +1468,7 @@ def RealVarVector(n, ctx=None):
>>> x2
Var(2)
"""
- return [ RealVar(i, ctx) for i in range(n) ]
+ return [RealVar(i, ctx) for i in range(n)]
#########################################
#
@@ -1395,8 +1476,10 @@ def RealVarVector(n, ctx=None):
#
#########################################
+
class BoolSortRef(SortRef):
"""Boolean sort."""
+
def cast(self, val):
"""Try to cast `val` as a Boolean.
@@ -1414,9 +1497,10 @@ class BoolSortRef(SortRef):
return BoolVal(val, self.ctx)
if z3_debug():
if not is_expr(val):
- _z3_assert(is_expr(val), "True, False or Z3 Boolean expression expected. Received %s of type %s" % (val, type(val)))
+ msg = "True, False or Z3 Boolean expression expected. Received %s of type %s"
+ _z3_assert(is_expr(val), msg % (val, type(val)))
if not self.eq(val.sort()):
- _z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
+ _z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
return val
def subsort(self, other):
@@ -1431,6 +1515,7 @@ class BoolSortRef(SortRef):
class BoolRef(ExprRef):
"""All Boolean expressions are instances of this class."""
+
def sort(self):
return BoolSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
@@ -1464,6 +1549,7 @@ def is_bool(a):
"""
return isinstance(a, BoolRef)
+
def is_true(a):
"""Return `True` if `a` is the Z3 true expression.
@@ -1481,6 +1567,7 @@ def is_true(a):
"""
return is_app_of(a, Z3_OP_TRUE)
+
def is_false(a):
"""Return `True` if `a` is the Z3 false expression.
@@ -1494,6 +1581,7 @@ def is_false(a):
"""
return is_app_of(a, Z3_OP_FALSE)
+
def is_and(a):
"""Return `True` if `a` is a Z3 and expression.
@@ -1505,6 +1593,7 @@ def is_and(a):
"""
return is_app_of(a, Z3_OP_AND)
+
def is_or(a):
"""Return `True` if `a` is a Z3 or expression.
@@ -1516,6 +1605,7 @@ def is_or(a):
"""
return is_app_of(a, Z3_OP_OR)
+
def is_implies(a):
"""Return `True` if `a` is a Z3 implication expression.
@@ -1527,6 +1617,7 @@ def is_implies(a):
"""
return is_app_of(a, Z3_OP_IMPLIES)
+
def is_not(a):
"""Return `True` if `a` is a Z3 not expression.
@@ -1538,6 +1629,7 @@ def is_not(a):
"""
return is_app_of(a, Z3_OP_NOT)
+
def is_eq(a):
"""Return `True` if `a` is a Z3 equality expression.
@@ -1547,6 +1639,7 @@ def is_eq(a):
"""
return is_app_of(a, Z3_OP_EQ)
+
def is_distinct(a):
"""Return `True` if `a` is a Z3 distinct expression.
@@ -1558,6 +1651,7 @@ def is_distinct(a):
"""
return is_app_of(a, Z3_OP_DISTINCT)
+
def BoolSort(ctx=None):
"""Return the Boolean Z3 sort. If `ctx=None`, then the global context is used.
@@ -1575,6 +1669,7 @@ def BoolSort(ctx=None):
ctx = _get_ctx(ctx)
return BoolSortRef(Z3_mk_bool_sort(ctx.ref()), ctx)
+
def BoolVal(val, ctx=None):
"""Return the Boolean value `True` or `False`. If `ctx=None`, then the global context is used.
@@ -1588,10 +1683,11 @@ def BoolVal(val, ctx=None):
True
"""
ctx = _get_ctx(ctx)
- if val == False:
- return BoolRef(Z3_mk_false(ctx.ref()), ctx)
- else:
+ if val:
return BoolRef(Z3_mk_true(ctx.ref()), ctx)
+ else:
+ return BoolRef(Z3_mk_false(ctx.ref()), ctx)
+
def Bool(name, ctx=None):
"""Return a Boolean constant named `name`. If `ctx=None`, then the global context is used.
@@ -1604,6 +1700,7 @@ def Bool(name, ctx=None):
ctx = _get_ctx(ctx)
return BoolRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), BoolSort(ctx).ast), ctx)
+
def Bools(names, ctx=None):
"""Return a tuple of Boolean constants.
@@ -1619,6 +1716,7 @@ def Bools(names, ctx=None):
names = names.split(" ")
return [Bool(name, ctx) for name in names]
+
def BoolVector(prefix, sz, ctx=None):
"""Return a list of Boolean constants of size `sz`.
@@ -1631,9 +1729,10 @@ def BoolVector(prefix, sz, ctx=None):
>>> And(P)
And(p__0, p__1, p__2)
"""
- return [ Bool('%s__%s' % (prefix, i)) for i in range(sz) ]
+ return [Bool("%s__%s" % (prefix, i)) for i in range(sz)]
-def FreshBool(prefix='b', ctx=None):
+
+def FreshBool(prefix="b", ctx=None):
"""Return a fresh Boolean constant in the given context using the given prefix.
If `ctx=None`, then the global context is used.
@@ -1646,6 +1745,7 @@ def FreshBool(prefix='b', ctx=None):
ctx = _get_ctx(ctx)
return BoolRef(Z3_mk_fresh_const(ctx.ref(), prefix, BoolSort(ctx).ast), ctx)
+
def Implies(a, b, ctx=None):
"""Create a Z3 implies expression.
@@ -1659,6 +1759,7 @@ def Implies(a, b, ctx=None):
b = s.cast(b)
return BoolRef(Z3_mk_implies(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
def Xor(a, b, ctx=None):
"""Create a Z3 Xor expression.
@@ -1674,6 +1775,7 @@ def Xor(a, b, ctx=None):
b = s.cast(b)
return BoolRef(Z3_mk_xor(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
def Not(a, ctx=None):
"""Create a Z3 not expression or probe.
@@ -1692,12 +1794,14 @@ def Not(a, ctx=None):
a = s.cast(a)
return BoolRef(Z3_mk_not(ctx.ref(), a.as_ast()), ctx)
+
def mk_not(a):
if is_not(a):
return a.arg(0)
else:
return Not(a)
+
def _has_probe(args):
"""Return `True` if one of the elements of the given collection is a Z3 probe."""
for arg in args:
@@ -1705,6 +1809,7 @@ def _has_probe(args):
return True
return False
+
def And(*args):
"""Create a Z3 and-expression or and-probe.
@@ -1717,26 +1822,27 @@ def And(*args):
"""
last_arg = None
if len(args) > 0:
- last_arg = args[len(args)-1]
+ last_arg = args[len(args) - 1]
if isinstance(last_arg, Context):
- ctx = args[len(args)-1]
- args = args[:len(args)-1]
+ ctx = args[len(args) - 1]
+ args = args[:len(args) - 1]
elif len(args) == 1 and isinstance(args[0], AstVector):
ctx = args[0].ctx
args = [a for a in args[0]]
else:
ctx = None
args = _get_args(args)
- ctx = _get_ctx(_ctx_from_ast_arg_list(args, ctx))
+ ctx = _get_ctx(_ctx_from_ast_arg_list(args, ctx))
if z3_debug():
_z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression or probe")
if _has_probe(args):
return _probe_and(args, ctx)
else:
- args = _coerce_expr_list(args, ctx)
+ args = _coerce_expr_list(args, ctx)
_args, sz = _to_ast_array(args)
return BoolRef(Z3_mk_and(ctx.ref(), sz, _args), ctx)
+
def Or(*args):
"""Create a Z3 or-expression or or-probe.
@@ -1749,23 +1855,23 @@ def Or(*args):
"""
last_arg = None
if len(args) > 0:
- last_arg = args[len(args)-1]
+ last_arg = args[len(args) - 1]
if isinstance(last_arg, Context):
- ctx = args[len(args)-1]
- args = args[:len(args)-1]
+ ctx = args[len(args) - 1]
+ args = args[:len(args) - 1]
elif len(args) == 1 and isinstance(args[0], AstVector):
ctx = args[0].ctx
args = [a for a in args[0]]
else:
ctx = None
args = _get_args(args)
- ctx = _get_ctx(_ctx_from_ast_arg_list(args, ctx))
+ ctx = _get_ctx(_ctx_from_ast_arg_list(args, ctx))
if z3_debug():
_z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression or probe")
if _has_probe(args):
return _probe_or(args, ctx)
else:
- args = _coerce_expr_list(args, ctx)
+ args = _coerce_expr_list(args, ctx)
_args, sz = _to_ast_array(args)
return BoolRef(Z3_mk_or(ctx.ref(), sz, _args), ctx)
@@ -1775,16 +1881,19 @@ def Or(*args):
#
#########################################
+
class PatternRef(ExprRef):
"""Patterns are hints for quantifier instantiation.
"""
+
def as_ast(self):
return Z3_pattern_to_ast(self.ctx_ref(), self.ast)
def get_id(self):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
+
def is_pattern(a):
"""Return `True` if `a` is a Z3 pattern (hint for quantifier instantiation.
@@ -1802,6 +1911,7 @@ def is_pattern(a):
"""
return isinstance(a, PatternRef)
+
def MultiPattern(*args):
"""Create a Z3 multi-pattern using the given expressions `*args`
@@ -1820,11 +1930,12 @@ def MultiPattern(*args):
"""
if z3_debug():
_z3_assert(len(args) > 0, "At least one argument expected")
- _z3_assert(all([ is_expr(a) for a in args ]), "Z3 expressions expected")
+ _z3_assert(all([is_expr(a) for a in args]), "Z3 expressions expected")
ctx = args[0].ctx
args, sz = _to_ast_array(args)
return PatternRef(Z3_mk_pattern(ctx.ref(), sz, args), ctx)
+
def _to_pattern(arg):
if is_pattern(arg):
return arg
@@ -1837,6 +1948,7 @@ def _to_pattern(arg):
#
#########################################
+
class QuantifierRef(BoolRef):
"""Universally and Existentially quantified formulas."""
@@ -1901,7 +2013,6 @@ class QuantifierRef(BoolRef):
_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)
-
def weight(self):
"""Return the weight annotation of `self`.
@@ -2021,7 +2132,8 @@ class QuantifierRef(BoolRef):
>>> q.children()
[f(Var(0)) == 0]
"""
- return [ self.body() ]
+ return [self.body()]
+
def is_quantifier(a):
"""Return `True` if `a` is a Z3 quantifier.
@@ -2036,10 +2148,11 @@ def is_quantifier(a):
"""
return isinstance(a, QuantifierRef)
+
def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
if z3_debug():
_z3_assert(is_bool(body) or is_app(vs) or (len(vs) > 0 and is_app(vs[0])), "Z3 expression expected")
- _z3_assert(is_const(vs) or (len(vs) > 0 and all([ is_const(v) for v in vs])), "Invalid bounded variable(s)")
+ _z3_assert(is_const(vs) or (len(vs) > 0 and all([is_const(v) for v in vs])), "Invalid bounded variable(s)")
_z3_assert(all([is_pattern(a) or is_expr(a) for a in patterns]), "Z3 patterns expected")
_z3_assert(all([is_expr(p) for p in no_patterns]), "no patterns are Z3 expressions")
if is_app(vs):
@@ -2048,21 +2161,21 @@ def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[],
else:
ctx = vs[0].ctx
if not is_expr(body):
- body = BoolVal(body, ctx)
+ body = BoolVal(body, ctx)
num_vars = len(vs)
if num_vars == 0:
return body
_vs = (Ast * num_vars)()
for i in range(num_vars):
- ## TODO: Check if is constant
+ # TODO: Check if is constant
_vs[i] = vs[i].as_ast()
- patterns = [ _to_pattern(p) for p in patterns ]
+ patterns = [_to_pattern(p) for p in patterns]
num_pats = len(patterns)
_pats = (Pattern * num_pats)()
for i in range(num_pats):
_pats[i] = patterns[i].ast
_no_pats, num_no_pats = _to_ast_array(no_patterns)
- qid = to_symbol(qid, ctx)
+ qid = to_symbol(qid, ctx)
skid = to_symbol(skid, ctx)
return QuantifierRef(Z3_mk_quantifier_const_ex(ctx.ref(), is_forall, weight, qid, skid,
num_vars, _vs,
@@ -2070,6 +2183,7 @@ def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[],
num_no_pats, _no_pats,
body.as_ast()), ctx)
+
def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""Create a Z3 forall formula.
@@ -2087,6 +2201,7 @@ def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""
return _mk_quantifier(True, vs, body, weight, qid, skid, patterns, no_patterns)
+
def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""Create a Z3 exists formula.
@@ -2107,6 +2222,7 @@ def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""
return _mk_quantifier(False, vs, body, weight, qid, skid, patterns, no_patterns)
+
def Lambda(vs, body):
"""Create a Z3 lambda expression.
@@ -2123,7 +2239,7 @@ def Lambda(vs, body):
num_vars = len(vs)
_vs = (Ast * num_vars)()
for i in range(num_vars):
- ## TODO: Check if is constant
+ # TODO: Check if is constant
_vs[i] = vs[i].as_ast()
return QuantifierRef(Z3_mk_lambda_const(ctx.ref(), num_vars, _vs, body.as_ast()), ctx)
@@ -2133,6 +2249,7 @@ def Lambda(vs, body):
#
#########################################
+
class ArithSortRef(SortRef):
"""Real and Integer sorts."""
@@ -2195,14 +2312,16 @@ class ArithSortRef(SortRef):
if val_s.is_bool() and self.is_real():
return ToReal(If(val, 1, 0))
if z3_debug():
- _z3_assert(False, "Z3 Integer/Real expression expected" )
+ _z3_assert(False, "Z3 Integer/Real expression expected")
else:
if self.is_int():
return IntVal(val, self.ctx)
if self.is_real():
return RealVal(val, self.ctx)
if z3_debug():
- _z3_assert(False, "int, long, float, string (numeral), or Z3 Integer/Real expression expected. Got %s" % self)
+ msg = "int, long, float, string (numeral), or Z3 Integer/Real expression expected. Got %s"
+ _z3_assert(False, msg % self)
+
def is_arith_sort(s):
"""Return `True` if s is an arithmetical sort (type).
@@ -2219,6 +2338,7 @@ def is_arith_sort(s):
"""
return isinstance(s, ArithSortRef)
+
class ArithRef(ExprRef):
"""Integer and Real expressions."""
@@ -2291,7 +2411,7 @@ class ArithRef(ExprRef):
Real
"""
if isinstance(other, BoolRef):
- return If(other, self, 0)
+ return If(other, self, 0)
a, b = _coerce_exprs(self, other)
return ArithRef(_mk_bin(Z3_mk_mul, a, b), self.ctx)
@@ -2503,6 +2623,7 @@ class ArithRef(ExprRef):
a, b = _coerce_exprs(self, other)
return BoolRef(Z3_mk_ge(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx)
+
def is_arith(a):
"""Return `True` if `a` is an arithmetical expression.
@@ -2523,6 +2644,7 @@ def is_arith(a):
"""
return isinstance(a, ArithRef)
+
def is_int(a):
"""Return `True` if `a` is an integer expression.
@@ -2541,6 +2663,7 @@ def is_int(a):
"""
return is_arith(a) and a.is_int()
+
def is_real(a):
"""Return `True` if `a` is a real expression.
@@ -2559,12 +2682,15 @@ def is_real(a):
"""
return is_arith(a) and a.is_real()
+
def _is_numeral(ctx, a):
return Z3_is_numeral_ast(ctx.ref(), a)
+
def _is_algebraic(ctx, a):
return Z3_is_algebraic_number(ctx.ref(), a)
+
def is_int_value(a):
"""Return `True` if `a` is an integer value of sort Int.
@@ -2588,6 +2714,7 @@ def is_int_value(a):
"""
return is_arith(a) and a.is_int() and _is_numeral(a.ctx, a.as_ast())
+
def is_rational_value(a):
"""Return `True` if `a` is rational value of sort Real.
@@ -2609,6 +2736,7 @@ def is_rational_value(a):
"""
return is_arith(a) and a.is_real() and _is_numeral(a.ctx, a.as_ast())
+
def is_algebraic_value(a):
"""Return `True` if `a` is an algebraic value of sort Real.
@@ -2622,6 +2750,7 @@ def is_algebraic_value(a):
"""
return is_arith(a) and a.is_real() and _is_algebraic(a.ctx, a.as_ast())
+
def is_add(a):
"""Return `True` if `a` is an expression of the form b + c.
@@ -2633,6 +2762,7 @@ def is_add(a):
"""
return is_app_of(a, Z3_OP_ADD)
+
def is_mul(a):
"""Return `True` if `a` is an expression of the form b * c.
@@ -2644,6 +2774,7 @@ def is_mul(a):
"""
return is_app_of(a, Z3_OP_MUL)
+
def is_sub(a):
"""Return `True` if `a` is an expression of the form b - c.
@@ -2655,6 +2786,7 @@ def is_sub(a):
"""
return is_app_of(a, Z3_OP_SUB)
+
def is_div(a):
"""Return `True` if `a` is an expression of the form b / c.
@@ -2671,6 +2803,7 @@ def is_div(a):
"""
return is_app_of(a, Z3_OP_DIV)
+
def is_idiv(a):
"""Return `True` if `a` is an expression of the form b div c.
@@ -2682,6 +2815,7 @@ def is_idiv(a):
"""
return is_app_of(a, Z3_OP_IDIV)
+
def is_mod(a):
"""Return `True` if `a` is an expression of the form b % c.
@@ -2693,6 +2827,7 @@ def is_mod(a):
"""
return is_app_of(a, Z3_OP_MOD)
+
def is_le(a):
"""Return `True` if `a` is an expression of the form b <= c.
@@ -2704,6 +2839,7 @@ def is_le(a):
"""
return is_app_of(a, Z3_OP_LE)
+
def is_lt(a):
"""Return `True` if `a` is an expression of the form b < c.
@@ -2715,6 +2851,7 @@ def is_lt(a):
"""
return is_app_of(a, Z3_OP_LT)
+
def is_ge(a):
"""Return `True` if `a` is an expression of the form b >= c.
@@ -2726,6 +2863,7 @@ def is_ge(a):
"""
return is_app_of(a, Z3_OP_GE)
+
def is_gt(a):
"""Return `True` if `a` is an expression of the form b > c.
@@ -2737,6 +2875,7 @@ def is_gt(a):
"""
return is_app_of(a, Z3_OP_GT)
+
def is_is_int(a):
"""Return `True` if `a` is an expression of the form IsInt(b).
@@ -2748,6 +2887,7 @@ def is_is_int(a):
"""
return is_app_of(a, Z3_OP_IS_INT)
+
def is_to_real(a):
"""Return `True` if `a` is an expression of the form ToReal(b).
@@ -2762,6 +2902,7 @@ def is_to_real(a):
"""
return is_app_of(a, Z3_OP_TO_REAL)
+
def is_to_int(a):
"""Return `True` if `a` is an expression of the form ToInt(b).
@@ -2776,6 +2917,7 @@ def is_to_int(a):
"""
return is_app_of(a, Z3_OP_TO_INT)
+
class IntNumRef(ArithRef):
"""Integer values."""
@@ -2808,6 +2950,7 @@ class IntNumRef(ArithRef):
"""
return Z3_get_numeral_binary_string(self.ctx_ref(), self.as_ast())
+
class RatNumRef(ArithRef):
"""Rational values."""
@@ -2904,6 +3047,7 @@ class RatNumRef(ArithRef):
"""
return Fraction(self.numerator_as_long(), self.denominator_as_long())
+
class AlgebraicNumRef(ArithRef):
"""Algebraic irrational values."""
@@ -2918,8 +3062,10 @@ class AlgebraicNumRef(ArithRef):
2965821/2097152
"""
return RatNumRef(Z3_get_algebraic_number_upper(self.ctx_ref(), self.as_ast(), precision), self.ctx)
+
def as_decimal(self, prec):
- """Return a string representation of the algebraic number `self` in decimal notation using `prec` decimal places
+ """Return a string representation of the algebraic number `self` in decimal notation
+ using `prec` decimal places.
>>> x = simplify(Sqrt(2))
>>> x.as_decimal(10)
@@ -2935,6 +3081,7 @@ class AlgebraicNumRef(ArithRef):
def index(self):
return Z3_algebraic_get_i(self.ctx_ref(), self.as_ast())
+
def _py2expr(a, ctx=None):
if isinstance(a, bool):
return BoolVal(a, ctx)
@@ -2949,6 +3096,7 @@ def _py2expr(a, ctx=None):
if z3_debug():
_z3_assert(False, "Python bool, int, long or float expected")
+
def IntSort(ctx=None):
"""Return the integer sort in the given context. If `ctx=None`, then the global context is used.
@@ -2965,6 +3113,7 @@ def IntSort(ctx=None):
ctx = _get_ctx(ctx)
return ArithSortRef(Z3_mk_int_sort(ctx.ref()), ctx)
+
def RealSort(ctx=None):
"""Return the real sort in the given context. If `ctx=None`, then the global context is used.
@@ -2981,6 +3130,7 @@ def RealSort(ctx=None):
ctx = _get_ctx(ctx)
return ArithSortRef(Z3_mk_real_sort(ctx.ref()), ctx)
+
def _to_int_str(val):
if isinstance(val, float):
return str(int(val))
@@ -2996,6 +3146,7 @@ def _to_int_str(val):
if z3_debug():
_z3_assert(False, "Python value cannot be used as a Z3 integer")
+
def IntVal(val, ctx=None):
"""Return a Z3 integer value. If `ctx=None`, then the global context is used.
@@ -3007,6 +3158,7 @@ def IntVal(val, ctx=None):
ctx = _get_ctx(ctx)
return IntNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), IntSort(ctx).ast), ctx)
+
def RealVal(val, ctx=None):
"""Return a Z3 real value.
@@ -3025,6 +3177,7 @@ def RealVal(val, ctx=None):
ctx = _get_ctx(ctx)
return RatNumRef(Z3_mk_numeral(ctx.ref(), str(val), RealSort(ctx).ast), ctx)
+
def RatVal(a, b, ctx=None):
"""Return a Z3 rational a/b.
@@ -3038,7 +3191,8 @@ def RatVal(a, b, ctx=None):
if z3_debug():
_z3_assert(_is_int(a) or isinstance(a, str), "First argument cannot be converted into an integer")
_z3_assert(_is_int(b) or isinstance(b, str), "Second argument cannot be converted into an integer")
- return simplify(RealVal(a, ctx)/RealVal(b, ctx))
+ return simplify(RealVal(a, ctx) / RealVal(b, ctx))
+
def Q(a, b, ctx=None):
"""Return a Z3 rational a/b.
@@ -3052,6 +3206,7 @@ def Q(a, b, ctx=None):
"""
return simplify(RatVal(a, b))
+
def Int(name, ctx=None):
"""Return an integer constant named `name`. If `ctx=None`, then the global context is used.
@@ -3064,6 +3219,7 @@ def Int(name, ctx=None):
ctx = _get_ctx(ctx)
return ArithRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), IntSort(ctx).ast), ctx)
+
def Ints(names, ctx=None):
"""Return a tuple of Integer constants.
@@ -3076,6 +3232,7 @@ def Ints(names, ctx=None):
names = names.split(" ")
return [Int(name, ctx) for name in names]
+
def IntVector(prefix, sz, ctx=None):
"""Return a list of integer constants of size `sz`.
@@ -3086,9 +3243,10 @@ def IntVector(prefix, sz, ctx=None):
x__0 + x__1 + x__2
"""
ctx = _get_ctx(ctx)
- return [ Int('%s__%s' % (prefix, i), ctx) for i in range(sz) ]
+ return [Int("%s__%s" % (prefix, i), ctx) for i in range(sz)]
-def FreshInt(prefix='x', ctx=None):
+
+def FreshInt(prefix="x", ctx=None):
"""Return a fresh integer constant in the given context using the given prefix.
>>> x = FreshInt()
@@ -3101,6 +3259,7 @@ def FreshInt(prefix='x', ctx=None):
ctx = _get_ctx(ctx)
return ArithRef(Z3_mk_fresh_const(ctx.ref(), prefix, IntSort(ctx).ast), ctx)
+
def Real(name, ctx=None):
"""Return a real constant named `name`. If `ctx=None`, then the global context is used.
@@ -3113,6 +3272,7 @@ def Real(name, ctx=None):
ctx = _get_ctx(ctx)
return ArithRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), RealSort(ctx).ast), ctx)
+
def Reals(names, ctx=None):
"""Return a tuple of real constants.
@@ -3127,6 +3287,7 @@ def Reals(names, ctx=None):
names = names.split(" ")
return [Real(name, ctx) for name in names]
+
def RealVector(prefix, sz, ctx=None):
"""Return a list of real constants of size `sz`.
@@ -3139,9 +3300,10 @@ def RealVector(prefix, sz, ctx=None):
Real
"""
ctx = _get_ctx(ctx)
- return [ Real('%s__%s' % (prefix, i), ctx) for i in range(sz) ]
+ return [Real("%s__%s" % (prefix, i), ctx) for i in range(sz)]
-def FreshReal(prefix='b', ctx=None):
+
+def FreshReal(prefix="b", ctx=None):
"""Return a fresh real constant in the given context using the given prefix.
>>> x = FreshReal()
@@ -3154,6 +3316,7 @@ def FreshReal(prefix='b', ctx=None):
ctx = _get_ctx(ctx)
return ArithRef(Z3_mk_fresh_const(ctx.ref(), prefix, RealSort(ctx).ast), ctx)
+
def ToReal(a):
""" Return the Z3 expression ToReal(a).
@@ -3171,6 +3334,7 @@ def ToReal(a):
ctx = a.ctx
return ArithRef(Z3_mk_int2real(ctx.ref(), a.as_ast()), ctx)
+
def ToInt(a):
""" Return the Z3 expression ToInt(a).
@@ -3188,6 +3352,7 @@ def ToInt(a):
ctx = a.ctx
return ArithRef(Z3_mk_real2int(ctx.ref(), a.as_ast()), ctx)
+
def IsInt(a):
""" Return the Z3 predicate IsInt(a).
@@ -3204,6 +3369,7 @@ def IsInt(a):
ctx = a.ctx
return BoolRef(Z3_mk_is_int(ctx.ref(), a.as_ast()), ctx)
+
def Sqrt(a, ctx=None):
""" Return a Z3 expression which represents the square root of a.
@@ -3216,6 +3382,7 @@ def Sqrt(a, ctx=None):
a = RealVal(a, ctx)
return a ** "1/2"
+
def Cbrt(a, ctx=None):
""" Return a Z3 expression which represents the cubic root of a.
@@ -3234,6 +3401,7 @@ def Cbrt(a, ctx=None):
#
#########################################
+
class BitVecSortRef(SortRef):
"""Bit-vector sort."""
@@ -3266,6 +3434,7 @@ class BitVecSortRef(SortRef):
else:
return BitVecVal(val, self)
+
def is_bv_sort(s):
"""Return True if `s` is a Z3 bit-vector sort.
@@ -3276,6 +3445,7 @@ def is_bv_sort(s):
"""
return isinstance(s, BitVecSortRef)
+
class BitVecRef(ExprRef):
"""Bit-vector expressions."""
@@ -3688,6 +3858,7 @@ class BitVecRef(ExprRef):
a, b = _coerce_exprs(self, other)
return BitVecRef(Z3_mk_bvshl(self.ctx_ref(), b.as_ast(), a.as_ast()), self.ctx)
+
class BitVecNumRef(BitVecRef):
"""Bit-vector values."""
@@ -3703,7 +3874,8 @@ class BitVecNumRef(BitVecRef):
return int(self.as_string())
def as_signed_long(self):
- """Return a Z3 bit-vector numeral as a Python long (bignum) numeral. The most significant bit is assumed to be the sign.
+ """Return a Z3 bit-vector numeral as a Python long (bignum) numeral.
+ The most significant bit is assumed to be the sign.
>>> BitVecVal(4, 3).as_signed_long()
-4
@@ -3729,7 +3901,7 @@ class BitVecNumRef(BitVecRef):
def as_binary_string(self):
return Z3_get_numeral_binary_string(self.ctx_ref(), self.as_ast())
-
+
def is_bv(a):
"""Return `True` if `a` is a Z3 bit-vector expression.
@@ -3744,6 +3916,7 @@ def is_bv(a):
"""
return isinstance(a, BitVecRef)
+
def is_bv_value(a):
"""Return `True` if `a` is a Z3 bit-vector numeral value.
@@ -3758,6 +3931,7 @@ def is_bv_value(a):
"""
return is_bv(a) and _is_numeral(a.ctx, a.as_ast())
+
def BV2Int(a, is_signed=False):
"""Return the Z3 expression BV2Int(a).
@@ -3777,9 +3951,10 @@ def BV2Int(a, is_signed=False):
if z3_debug():
_z3_assert(is_bv(a), "First argument must be a Z3 bit-vector expression")
ctx = a.ctx
- ## investigate problem with bv2int
+ # investigate problem with bv2int
return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx)
+
def Int2BV(a, num_bits):
"""Return the z3 expression Int2BV(a, num_bits).
It is a bit-vector of width num_bits and represents the
@@ -3788,6 +3963,7 @@ def Int2BV(a, num_bits):
ctx = a.ctx
return BitVecRef(Z3_mk_int2bv(ctx.ref(), num_bits, a.as_ast()), ctx)
+
def BitVecSort(sz, ctx=None):
"""Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used.
@@ -3802,6 +3978,7 @@ def BitVecSort(sz, ctx=None):
ctx = _get_ctx(ctx)
return BitVecSortRef(Z3_mk_bv_sort(ctx.ref(), sz), ctx)
+
def BitVecVal(val, bv, ctx=None):
"""Return a bit-vector value with the given number of bits. If `ctx=None`, then the global context is used.
@@ -3818,6 +3995,7 @@ def BitVecVal(val, bv, ctx=None):
ctx = _get_ctx(ctx)
return BitVecNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), BitVecSort(bv, ctx).ast), ctx)
+
def BitVec(name, bv, ctx=None):
"""Return a bit-vector constant named `name`. `bv` may be the number of bits of a bit-vector sort.
If `ctx=None`, then the global context is used.
@@ -3841,6 +4019,7 @@ def BitVec(name, bv, ctx=None):
bv = BitVecSort(bv, ctx)
return BitVecRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), bv.ast), ctx)
+
def BitVecs(names, bv, ctx=None):
"""Return a tuple of bit-vector constants of size bv.
@@ -3861,6 +4040,7 @@ def BitVecs(names, bv, ctx=None):
names = names.split(" ")
return [BitVec(name, bv, ctx) for name in names]
+
def Concat(*args):
"""Create a Z3 bit-vector concatenation expression.
@@ -3892,22 +4072,29 @@ def Concat(*args):
return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx)
if is_re(args[0]):
- if z3_debug():
- _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.")
- v = (Ast * sz)()
- for i in range(sz):
- v[i] = args[i].as_ast()
- return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx)
+ if z3_debug():
+ _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.")
+ v = (Ast * sz)()
+ for i in range(sz):
+ v[i] = args[i].as_ast()
+ return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx)
if z3_debug():
_z3_assert(all([is_bv(a) for a in args]), "All arguments must be Z3 bit-vector expressions.")
- r = args[0]
+ r = args[0]
for i in range(sz - 1):
- r = BitVecRef(Z3_mk_concat(ctx.ref(), r.as_ast(), args[i+1].as_ast()), ctx)
+ r = BitVecRef(Z3_mk_concat(ctx.ref(), r.as_ast(), args[i + 1].as_ast()), ctx)
return r
+
def Extract(high, low, a):
- """Create a Z3 bit-vector extraction expression, or create a string extraction expression.
+ """Create a Z3 bit-vector extraction expression.
+ Extract is overloaded to also work on sequence extraction.
+ The functions SubString and SubSeq are redirected to Extract.
+ For this case, the arguments are reinterpreted as:
+ high - is a sequence (string)
+ low - is an offset
+ a - is the length to be extracted
>>> x = BitVec('x', 8)
>>> Extract(6, 2, x)
@@ -3925,14 +4112,17 @@ def Extract(high, low, a):
return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx)
if z3_debug():
_z3_assert(low <= high, "First argument must be greater than or equal to second argument")
- _z3_assert(_is_int(high) and high >= 0 and _is_int(low) and low >= 0, "First and second arguments must be non negative integers")
+ _z3_assert(_is_int(high) and high >= 0 and _is_int(low) and low >= 0,
+ "First and second arguments must be non negative integers")
_z3_assert(is_bv(a), "Third argument must be a Z3 bit-vector expression")
return BitVecRef(Z3_mk_extract(a.ctx_ref(), high, low, a.as_ast()), a.ctx)
+
def _check_bv_args(a, b):
if z3_debug():
_z3_assert(is_bv(a) or is_bv(b), "First or second argument must be a Z3 bit-vector expression")
+
def ULE(a, b):
"""Create the Z3 expression (unsigned) `other <= self`.
@@ -3950,6 +4140,7 @@ def ULE(a, b):
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvule(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def ULT(a, b):
"""Create the Z3 expression (unsigned) `other < self`.
@@ -3967,6 +4158,7 @@ def ULT(a, b):
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvult(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def UGE(a, b):
"""Create the Z3 expression (unsigned) `other >= self`.
@@ -3984,6 +4176,7 @@ def UGE(a, b):
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvuge(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def UGT(a, b):
"""Create the Z3 expression (unsigned) `other > self`.
@@ -4001,6 +4194,7 @@ def UGT(a, b):
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvugt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def UDiv(a, b):
"""Create the Z3 expression (unsigned) division `self / other`.
@@ -4021,6 +4215,7 @@ def UDiv(a, b):
a, b = _coerce_exprs(a, b)
return BitVecRef(Z3_mk_bvudiv(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def URem(a, b):
"""Create the Z3 expression (unsigned) remainder `self % other`.
@@ -4041,6 +4236,7 @@ def URem(a, b):
a, b = _coerce_exprs(a, b)
return BitVecRef(Z3_mk_bvurem(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def SRem(a, b):
"""Create the Z3 expression signed remainder.
@@ -4061,6 +4257,7 @@ def SRem(a, b):
a, b = _coerce_exprs(a, b)
return BitVecRef(Z3_mk_bvsrem(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def LShR(a, b):
"""Create the Z3 expression logical right shift.
@@ -4092,6 +4289,7 @@ def LShR(a, b):
a, b = _coerce_exprs(a, b)
return BitVecRef(Z3_mk_bvlshr(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def RotateLeft(a, b):
"""Return an expression representing `a` rotated to the left `b` times.
@@ -4107,6 +4305,7 @@ def RotateLeft(a, b):
a, b = _coerce_exprs(a, b)
return BitVecRef(Z3_mk_ext_rotate_left(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def RotateRight(a, b):
"""Return an expression representing `a` rotated to the right `b` times.
@@ -4122,6 +4321,7 @@ def RotateRight(a, b):
a, b = _coerce_exprs(a, b)
return BitVecRef(Z3_mk_ext_rotate_right(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def SignExt(n, a):
"""Return a bit-vector expression with `n` extra sign-bits.
@@ -4151,6 +4351,7 @@ def SignExt(n, a):
_z3_assert(is_bv(a), "Second argument must be a Z3 bit-vector expression")
return BitVecRef(Z3_mk_sign_ext(a.ctx_ref(), n, a.as_ast()), a.ctx)
+
def ZeroExt(n, a):
"""Return a bit-vector expression with `n` extra zero-bits.
@@ -4178,6 +4379,7 @@ def ZeroExt(n, a):
_z3_assert(is_bv(a), "Second argument must be a Z3 bit-vector expression")
return BitVecRef(Z3_mk_zero_ext(a.ctx_ref(), n, a.as_ast()), a.ctx)
+
def RepeatBitVec(n, a):
"""Return an expression representing `n` copies of `a`.
@@ -4201,30 +4403,35 @@ def RepeatBitVec(n, a):
_z3_assert(is_bv(a), "Second argument must be a Z3 bit-vector expression")
return BitVecRef(Z3_mk_repeat(a.ctx_ref(), n, a.as_ast()), a.ctx)
+
def BVRedAnd(a):
"""Return the reduction-and expression of `a`."""
if z3_debug():
_z3_assert(is_bv(a), "First argument must be a Z3 bit-vector expression")
return BitVecRef(Z3_mk_bvredand(a.ctx_ref(), a.as_ast()), a.ctx)
+
def BVRedOr(a):
"""Return the reduction-or expression of `a`."""
if z3_debug():
_z3_assert(is_bv(a), "First argument must be a Z3 bit-vector expression")
return BitVecRef(Z3_mk_bvredor(a.ctx_ref(), a.as_ast()), a.ctx)
+
def BVAddNoOverflow(a, b, signed):
"""A predicate the determines that bit-vector addition does not overflow"""
_check_bv_args(a, b)
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvadd_no_overflow(a.ctx_ref(), a.as_ast(), b.as_ast(), signed), a.ctx)
+
def BVAddNoUnderflow(a, b):
"""A predicate the determines that signed bit-vector addition does not underflow"""
_check_bv_args(a, b)
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvadd_no_underflow(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def BVSubNoOverflow(a, b):
"""A predicate the determines that bit-vector subtraction does not overflow"""
_check_bv_args(a, b)
@@ -4238,18 +4445,21 @@ def BVSubNoUnderflow(a, b, signed):
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvsub_no_underflow(a.ctx_ref(), a.as_ast(), b.as_ast(), signed), a.ctx)
+
def BVSDivNoOverflow(a, b):
"""A predicate the determines that bit-vector signed division does not overflow"""
_check_bv_args(a, b)
a, b = _coerce_exprs(a, b)
return BoolRef(Z3_mk_bvsdiv_no_overflow(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def BVSNegNoOverflow(a):
"""A predicate the determines that bit-vector unary negation does not overflow"""
if z3_debug():
_z3_assert(is_bv(a), "First argument must be a Z3 bit-vector expression")
return BoolRef(Z3_mk_bvneg_no_overflow(a.ctx_ref(), a.as_ast()), a.ctx)
+
def BVMulNoOverflow(a, b, signed):
"""A predicate the determines that bit-vector multiplication does not overflow"""
_check_bv_args(a, b)
@@ -4264,7 +4474,6 @@ def BVMulNoUnderflow(a, b):
return BoolRef(Z3_mk_bvmul_no_underflow(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
-
#########################################
#
# Arrays
@@ -4292,6 +4501,7 @@ class ArraySortRef(SortRef):
"""
return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx)
+
class ArrayRef(ExprRef):
"""Array expressions. """
@@ -4338,6 +4548,7 @@ class ArrayRef(ExprRef):
def default(self):
return _to_expr_ref(Z3_mk_array_default(self.ctx_ref(), self.as_ast()), self.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
@@ -4355,6 +4566,7 @@ def is_array(a):
"""
return isinstance(a, ArrayRef)
+
def is_const_array(a):
"""Return `True` if `a` is a Z3 constant array.
@@ -4367,6 +4579,7 @@ def is_const_array(a):
"""
return is_app_of(a, Z3_OP_CONST_ARRAY)
+
def is_K(a):
"""Return `True` if `a` is a Z3 constant array.
@@ -4379,6 +4592,7 @@ def is_K(a):
"""
return is_app_of(a, Z3_OP_CONST_ARRAY)
+
def is_map(a):
"""Return `True` if `a` is a Z3 map array expression.
@@ -4394,6 +4608,7 @@ def is_map(a):
"""
return is_app_of(a, Z3_OP_ARRAY_MAP)
+
def is_default(a):
"""Return `True` if `a` is a Z3 default array expression.
>>> d = Default(K(IntSort(), 10))
@@ -4402,6 +4617,7 @@ def is_default(a):
"""
return is_app_of(a, Z3_OP_ARRAY_DEFAULT)
+
def get_map_func(a):
"""Return the function declaration associated with a Z3 map array expression.
@@ -4417,7 +4633,14 @@ def get_map_func(a):
"""
if z3_debug():
_z3_assert(is_map(a), "Z3 array map expression expected.")
- return FuncDeclRef(Z3_to_func_decl(a.ctx_ref(), Z3_get_decl_ast_parameter(a.ctx_ref(), a.decl().ast, 0)), a.ctx)
+ return FuncDeclRef(
+ Z3_to_func_decl(
+ a.ctx_ref(),
+ Z3_get_decl_ast_parameter(a.ctx_ref(), a.decl().ast, 0),
+ ),
+ ctx=a.ctx,
+ )
+
def ArraySort(*sig):
"""Return the Z3 array sort with the given domain and range sorts.
@@ -4451,6 +4674,7 @@ def ArraySort(*sig):
dom[i] = sig[i].ast
return ArraySortRef(Z3_mk_array_sort_n(ctx.ref(), arity, dom, r.ast), ctx)
+
def Array(name, dom, rng):
"""Return an array constant named `name` with the given domain and range sorts.
@@ -4464,6 +4688,7 @@ def Array(name, dom, rng):
ctx = s.ctx
return ArrayRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), s.ast), ctx)
+
def Update(a, i, v):
"""Return a Z3 store array expression.
@@ -4485,6 +4710,7 @@ def Update(a, i, v):
ctx = a.ctx
return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx)
+
def Default(a):
""" Return a default value for array expression.
>>> b = K(IntSort(), 1)
@@ -4512,6 +4738,7 @@ def Store(a, i, v):
"""
return Update(a, i, v)
+
def Select(a, i):
"""Return a Z3 select array expression.
@@ -4549,6 +4776,7 @@ def Map(f, *args):
ctx = f.ctx
return ArrayRef(Z3_mk_map(ctx.ref(), f.ast, sz, _args), ctx)
+
def K(dom, v):
"""Return a Z3 constant array expression.
@@ -4570,6 +4798,7 @@ def K(dom, v):
v = _py2expr(v, ctx)
return ArrayRef(Z3_mk_const_array(ctx.ref(), dom.ast, v.as_ast()), ctx)
+
def Ext(a, b):
"""Return extensionality index for one-dimensional arrays.
>> a, b = Consts('a b', SetSort(IntSort()))
@@ -4581,11 +4810,13 @@ def Ext(a, b):
_z3_assert(is_array_sort(a) and is_array(b), "arguments must be arrays")
return _to_expr_ref(Z3_mk_array_ext(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
def SetHasSize(a, k):
ctx = a.ctx
k = _py2expr(k, ctx)
return _to_expr_ref(Z3_mk_set_has_size(ctx.ref(), a.as_ast(), k.as_ast()), ctx)
+
def is_select(a):
"""Return `True` if `a` is a Z3 array select application.
@@ -4598,6 +4829,7 @@ def is_select(a):
"""
return is_app_of(a, Z3_OP_SELECT)
+
def is_store(a):
"""Return `True` if `a` is a Z3 array store application.
@@ -4620,6 +4852,7 @@ def SetSort(s):
""" Create a set sort over element sort s"""
return ArraySort(s, BoolSort())
+
def EmptySet(s):
"""Create the empty set
>>> EmptySet(IntSort())
@@ -4628,6 +4861,7 @@ def EmptySet(s):
ctx = s.ctx
return ArrayRef(Z3_mk_empty_set(ctx.ref(), s.ast), ctx)
+
def FullSet(s):
"""Create the full set
>>> FullSet(IntSort())
@@ -4636,6 +4870,7 @@ def FullSet(s):
ctx = s.ctx
return ArrayRef(Z3_mk_full_set(ctx.ref(), s.ast), ctx)
+
def SetUnion(*args):
""" Take the union of sets
>>> a = Const('a', SetSort(IntSort()))
@@ -4648,6 +4883,7 @@ def SetUnion(*args):
_args, sz = _to_ast_array(args)
return ArrayRef(Z3_mk_set_union(ctx.ref(), sz, _args), ctx)
+
def SetIntersect(*args):
""" Take the union of sets
>>> a = Const('a', SetSort(IntSort()))
@@ -4660,26 +4896,29 @@ def SetIntersect(*args):
_args, sz = _to_ast_array(args)
return ArrayRef(Z3_mk_set_intersect(ctx.ref(), sz, _args), ctx)
+
def SetAdd(s, e):
""" Add element e to set s
>>> a = Const('a', SetSort(IntSort()))
>>> SetAdd(a, 1)
Store(a, 1, True)
"""
- ctx = _ctx_from_ast_arg_list([s,e])
+ ctx = _ctx_from_ast_arg_list([s, e])
e = _py2expr(e, ctx)
return ArrayRef(Z3_mk_set_add(ctx.ref(), s.as_ast(), e.as_ast()), ctx)
+
def SetDel(s, e):
""" Remove element e to set s
>>> a = Const('a', SetSort(IntSort()))
>>> SetDel(a, 1)
Store(a, 1, False)
"""
- ctx = _ctx_from_ast_arg_list([s,e])
+ ctx = _ctx_from_ast_arg_list([s, e])
e = _py2expr(e, ctx)
return ArrayRef(Z3_mk_set_del(ctx.ref(), s.as_ast(), e.as_ast()), ctx)
+
def SetComplement(s):
""" The complement of set s
>>> a = Const('a', SetSort(IntSort()))
@@ -4689,6 +4928,7 @@ def SetComplement(s):
ctx = s.ctx
return ArrayRef(Z3_mk_set_complement(ctx.ref(), s.as_ast()), ctx)
+
def SetDifference(a, b):
""" The set difference of a and b
>>> a = Const('a', SetSort(IntSort()))
@@ -4699,16 +4939,18 @@ def SetDifference(a, b):
ctx = _ctx_from_ast_arg_list([a, b])
return ArrayRef(Z3_mk_set_difference(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
def IsMember(e, s):
""" Check if e is a member of set s
>>> a = Const('a', SetSort(IntSort()))
>>> IsMember(1, a)
a[1]
"""
- ctx = _ctx_from_ast_arg_list([s,e])
+ ctx = _ctx_from_ast_arg_list([s, e])
e = _py2expr(e, ctx)
return BoolRef(Z3_mk_set_member(ctx.ref(), e.as_ast(), s.as_ast()), ctx)
+
def IsSubset(a, b):
""" Check if a is a subset of b
>>> a = Const('a', SetSort(IntSort()))
@@ -4728,7 +4970,12 @@ def IsSubset(a, b):
def _valid_accessor(acc):
"""Return `True` if acc is pair of the form (String, Datatype or Sort). """
- return isinstance(acc, tuple) and len(acc) == 2 and isinstance(acc[0], str) and (isinstance(acc[1], Datatype) or is_sort(acc[1]))
+ if not isinstance(acc, tuple):
+ return False
+ if len(acc) != 2:
+ return False
+ return isinstance(acc[0], str) and (isinstance(acc[1], Datatype) or is_sort(acc[1]))
+
class Datatype:
"""Helper class for declaring Z3 datatypes.
@@ -4756,9 +5003,10 @@ class Datatype:
>>> simplify(car(n))
1
"""
+
def __init__(self, name, ctx=None):
- self.ctx = _get_ctx(ctx)
- self.name = name
+ self.ctx = _get_ctx(ctx)
+ self.name = name
self.constructors = []
def __deepcopy__(self, memo={}):
@@ -4770,18 +5018,22 @@ class Datatype:
if z3_debug():
_z3_assert(isinstance(name, str), "String expected")
_z3_assert(isinstance(rec_name, str), "String expected")
- _z3_assert(all([_valid_accessor(a) for a in args]), "Valid list of accessors expected. An accessor is a pair of the form (String, Datatype|Sort)")
+ _z3_assert(
+ all([_valid_accessor(a) for a in args]),
+ "Valid list of accessors expected. An accessor is a pair of the form (String, Datatype|Sort)",
+ )
self.constructors.append((name, rec_name, args))
def declare(self, name, *args):
"""Declare constructor named `name` with the given accessors `args`.
- Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort or a reference to the datatypes being declared.
+ Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort
+ or a reference to the datatypes being declared.
In the following example `List.declare('cons', ('car', IntSort()), ('cdr', List))`
declares the constructor named `cons` that builds a new List using an integer and a List.
- It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer of a `cons` cell,
- and `cdr` the list of a `cons` cell. After all constructors were declared, we use the method create() to create
- the actual datatype in Z3.
+ It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer
+ of a `cons` cell, and `cdr` the list of a `cons` cell. After all constructors were declared,
+ we use the method create() to create the actual datatype in Z3.
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
@@ -4812,23 +5064,30 @@ class Datatype:
"""
return CreateDatatypes([self])[0]
+
class ScopedConstructor:
"""Auxiliary object used to create Z3 datatypes."""
+
def __init__(self, c, ctx):
- self.c = c
+ self.c = c
self.ctx = ctx
+
def __del__(self):
if self.ctx.ref() is not None:
- Z3_del_constructor(self.ctx.ref(), self.c)
+ Z3_del_constructor(self.ctx.ref(), self.c)
+
class ScopedConstructorList:
"""Auxiliary object used to create Z3 datatypes."""
+
def __init__(self, c, ctx):
- self.c = c
+ self.c = c
self.ctx = ctx
+
def __del__(self):
if self.ctx.ref() is not None:
- Z3_del_constructor_list(self.ctx.ref(), self.c)
+ Z3_del_constructor_list(self.ctx.ref(), self.c)
+
def CreateDatatypes(*ds):
"""Create mutually recursive Z3 datatypes using 1 or more Datatype helper objects.
@@ -4861,60 +5120,63 @@ def CreateDatatypes(*ds):
if z3_debug():
_z3_assert(len(ds) > 0, "At least one Datatype must be specified")
_z3_assert(all([isinstance(d, Datatype) for d in ds]), "Arguments must be Datatypes")
- _z3_assert(all([d.ctx == ds[0].ctx for d in ds]), "Context mismatch")
+ _z3_assert(all([d.ctx == ds[0].ctx for d in ds]), "Context mismatch")
_z3_assert(all([d.constructors != [] for d in ds]), "Non-empty Datatypes expected")
ctx = ds[0].ctx
- num = len(ds)
- names = (Symbol * num)()
- out = (Sort * num)()
+ num = len(ds)
+ names = (Symbol * num)()
+ out = (Sort * num)()
clists = (ConstructorList * num)()
to_delete = []
for i in range(num):
- d = ds[i]
+ d = ds[i]
names[i] = to_symbol(d.name, ctx)
- num_cs = len(d.constructors)
- cs = (Constructor * num_cs)()
+ num_cs = len(d.constructors)
+ cs = (Constructor * num_cs)()
for j in range(num_cs):
- c = d.constructors[j]
- cname = to_symbol(c[0], ctx)
- rname = to_symbol(c[1], ctx)
- fs = c[2]
+ c = d.constructors[j]
+ cname = to_symbol(c[0], ctx)
+ rname = to_symbol(c[1], ctx)
+ fs = c[2]
num_fs = len(fs)
fnames = (Symbol * num_fs)()
- sorts = (Sort * num_fs)()
- refs = (ctypes.c_uint * num_fs)()
+ sorts = (Sort * num_fs)()
+ refs = (ctypes.c_uint * num_fs)()
for k in range(num_fs):
fname = fs[k][0]
ftype = fs[k][1]
fnames[k] = to_symbol(fname, ctx)
if isinstance(ftype, Datatype):
if z3_debug():
- _z3_assert(ds.count(ftype) == 1, "One and only one occurrence of each datatype is expected")
+ _z3_assert(
+ ds.count(ftype) == 1,
+ "One and only one occurrence of each datatype is expected",
+ )
sorts[k] = None
- refs[k] = ds.index(ftype)
+ refs[k] = ds.index(ftype)
else:
if z3_debug():
_z3_assert(is_sort(ftype), "Z3 sort expected")
sorts[k] = ftype.ast
- refs[k] = 0
+ refs[k] = 0
cs[j] = Z3_mk_constructor(ctx.ref(), cname, rname, num_fs, fnames, sorts, refs)
to_delete.append(ScopedConstructor(cs[j], ctx))
clists[i] = Z3_mk_constructor_list(ctx.ref(), num_cs, cs)
to_delete.append(ScopedConstructorList(clists[i], ctx))
Z3_mk_datatypes(ctx.ref(), num, names, out, clists)
result = []
- ## Create a field for every constructor, recognizer and accessor
+ # Create a field for every constructor, recognizer and accessor
for i in range(num):
dref = DatatypeSortRef(out[i], ctx)
num_cs = dref.num_constructors()
for j in range(num_cs):
- cref = dref.constructor(j)
- cref_name = cref.name()
+ cref = dref.constructor(j)
+ cref_name = cref.name()
cref_arity = cref.arity()
if cref.arity() == 0:
cref = cref()
setattr(dref, cref_name, cref)
- rref = dref.recognizer(j)
+ rref = dref.recognizer(j)
setattr(dref, "is_" + cref_name, rref)
for k in range(cref_arity):
aref = dref.accessor(j, k)
@@ -4922,8 +5184,10 @@ def CreateDatatypes(*ds):
result.append(dref)
return tuple(result)
+
class DatatypeSortRef(SortRef):
"""Datatype sorts."""
+
def num_constructors(self):
"""Return the number of constructors in the given Z3 datatype.
@@ -4985,7 +5249,8 @@ class DatatypeSortRef(SortRef):
return FuncDeclRef(Z3_get_datatype_sort_recognizer(self.ctx_ref(), self.ast, idx), self.ctx)
def accessor(self, i, j):
- """In Z3, each constructor has 0 or more accessor. The number of accessors is equal to the arity of the constructor.
+ """In Z3, each constructor has 0 or more accessor.
+ The number of accessors is equal to the arity of the constructor.
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
@@ -5011,25 +5276,32 @@ class DatatypeSortRef(SortRef):
if z3_debug():
_z3_assert(i < self.num_constructors(), "Invalid constructor index")
_z3_assert(j < self.constructor(i).arity(), "Invalid accessor index")
- return FuncDeclRef(Z3_get_datatype_sort_constructor_accessor(self.ctx_ref(), self.ast, i, j), self.ctx)
+ return FuncDeclRef(
+ Z3_get_datatype_sort_constructor_accessor(self.ctx_ref(), self.ast, i, j),
+ ctx=self.ctx,
+ )
+
class DatatypeRef(ExprRef):
"""Datatype expressions."""
+
def sort(self):
"""Return the datatype sort of the datatype expression `self`."""
return DatatypeSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
-def TupleSort(name, sorts, ctx = None):
+
+def TupleSort(name, sorts, ctx=None):
"""Create a named tuple sort base on a set of underlying sorts
Example:
>>> pair, mk_pair, (first, second) = TupleSort("pair", [IntSort(), StringSort()])
"""
tuple = Datatype(name, ctx)
- projects = [ ('project%d' % i, sorts[i]) for i in range(len(sorts)) ]
+ projects = [("project%d" % i, sorts[i]) for i in range(len(sorts))]
tuple.declare(name, *projects)
tuple = tuple.create()
return tuple, tuple.constructor(0), [tuple.accessor(0, i) for i in range(len(sorts))]
+
def DisjointSum(name, sorts, ctx=None):
"""Create a named tagged union sort base on a set of underlying sorts
Example:
@@ -5055,10 +5327,10 @@ def EnumSort(name, values, ctx=None):
_z3_assert(len(values) > 0, "At least one value expected")
ctx = _get_ctx(ctx)
num = len(values)
- _val_names = (Symbol * num)()
+ _val_names = (Symbol * num)()
for i in range(num):
_val_names[i] = to_symbol(values[i])
- _values = (FuncDecl * num)()
+ _values = (FuncDecl * num)()
_testers = (FuncDecl * num)()
name = to_symbol(name)
S = DatatypeSortRef(Z3_mk_enumeration_sort(ctx.ref(), name, num, _val_names, _values, _testers), ctx)
@@ -5074,13 +5346,15 @@ def EnumSort(name, values, ctx=None):
#
#########################################
+
class ParamsRef:
"""Set of parameters used to configure Solvers, Tactics and Simplifiers in Z3.
Consider using the function `args2params` to create instances of this object.
"""
+
def __init__(self, ctx=None, params=None):
- self.ctx = _get_ctx(ctx)
+ self.ctx = _get_ctx(ctx)
if params is None:
self.params = Z3_mk_params(self.ctx.ref())
else:
@@ -5092,7 +5366,7 @@ class ParamsRef:
def __del__(self):
if self.ctx.ref() is not None:
- Z3_params_dec_ref(self.ctx.ref(), self.params)
+ Z3_params_dec_ref(self.ctx.ref(), self.params)
def set(self, name, val):
"""Set parameter name with value val."""
@@ -5118,6 +5392,7 @@ class ParamsRef:
_z3_assert(isinstance(ds, ParamDescrsRef), "parameter description set expected")
Z3_params_validate(self.ctx.ref(), self.params, ds.descr)
+
def args2params(arguments, keywords, ctx=None):
"""Convert python arguments into a Z3_params object.
A ':' is added to the keywords, and '_' is replaced with '-'
@@ -5128,7 +5403,7 @@ def args2params(arguments, keywords, ctx=None):
if z3_debug():
_z3_assert(len(arguments) % 2 == 0, "Argument list must have an even number of elements.")
prev = None
- r = ParamsRef(ctx)
+ r = ParamsRef(ctx)
for a in arguments:
if prev is None:
prev = a
@@ -5140,13 +5415,15 @@ def args2params(arguments, keywords, ctx=None):
r.set(k, v)
return r
+
class ParamDescrsRef:
"""Set of parameter descriptions for Solvers, Tactics and Simplifiers in Z3.
"""
+
def __init__(self, descr, ctx=None):
_z3_assert(isinstance(descr, ParamDescrs), "parameter description object expected")
- self.ctx = _get_ctx(ctx)
- self.descr = descr
+ self.ctx = _get_ctx(ctx)
+ self.descr = descr
Z3_param_descrs_inc_ref(self.ctx.ref(), self.descr)
def __deepcopy__(self, memo={}):
@@ -5154,7 +5431,7 @@ class ParamDescrsRef:
def __del__(self):
if self.ctx.ref() is not None:
- Z3_param_descrs_dec_ref(self.ctx.ref(), self.descr)
+ Z3_param_descrs_dec_ref(self.ctx.ref(), self.descr)
def size(self):
"""Return the size of in the parameter description `self`.
@@ -5196,6 +5473,7 @@ class ParamDescrsRef:
#
#########################################
+
class Goal(Z3PPObject):
"""Goal is a collection of constraints we want to find a solution or show to be unsatisfiable (infeasible).
@@ -5206,22 +5484,21 @@ class Goal(Z3PPObject):
def __init__(self, models=True, unsat_cores=False, proofs=False, ctx=None, goal=None):
if z3_debug():
- _z3_assert(goal is None or ctx is not None, "If goal is different from None, then ctx must be also different from None")
- self.ctx = _get_ctx(ctx)
- self.goal = goal
+ _z3_assert(goal is None or ctx is not None,
+ "If goal is different from None, then ctx must be also different from None")
+ self.ctx = _get_ctx(ctx)
+ self.goal = goal
if self.goal is None:
- self.goal = Z3_mk_goal(self.ctx.ref(), models, unsat_cores, proofs)
+ self.goal = Z3_mk_goal(self.ctx.ref(), models, unsat_cores, proofs)
Z3_goal_inc_ref(self.ctx.ref(), self.goal)
- def __deepcopy__(self, memo={}):
- return Goal(False, False, False, self.ctx, self.goal)
-
def __del__(self):
if self.goal is not None and self.ctx.ref() is not None:
Z3_goal_dec_ref(self.ctx.ref(), self.goal)
def depth(self):
- """Return the depth of the goal `self`. The depth corresponds to the number of tactics applied to `self`.
+ """Return the depth of the goal `self`.
+ The depth corresponds to the number of tactics applied to `self`.
>>> x, y = Ints('x y')
>>> g = Goal()
@@ -5349,7 +5626,7 @@ class Goal(Z3PPObject):
[x > 0, x < 2]
"""
args = _get_args(args)
- s = BoolSort(self.ctx)
+ s = BoolSort(self.ctx)
for arg in args:
arg = s.cast(arg)
Z3_goal_assert(self.ctx.ref(), self.goal, arg.as_ast())
@@ -5423,7 +5700,7 @@ class Goal(Z3PPObject):
"""Return a textual representation of the s-expression representing the goal."""
return Z3_goal_to_string(self.ctx.ref(), self.goal)
- def dimacs(self, include_names = True):
+ def dimacs(self, include_names=True):
"""Return a textual representation of the goal in DIMACS format."""
return Z3_goal_to_dimacs_string(self.ctx.ref(), self.goal, include_names)
@@ -5473,7 +5750,7 @@ class Goal(Z3PPObject):
>>> g
[x + 1 >= 2]
"""
- t = Tactic('simplify')
+ t = Tactic("simplify")
return t.apply(self, *arguments, **keywords)[0]
def as_expr(self):
@@ -5496,13 +5773,15 @@ class Goal(Z3PPObject):
elif sz == 1:
return self.get(0)
else:
- return And([ self.get(i) for i in range(len(self)) ], self.ctx)
+ return And([self.get(i) for i in range(len(self))], self.ctx)
#########################################
#
# AST Vector
#
#########################################
+
+
class AstVector(Z3PPObject):
"""A collection (vector) of ASTs."""
@@ -5514,12 +5793,9 @@ class AstVector(Z3PPObject):
else:
self.vector = v
assert ctx is not None
- self.ctx = ctx
+ self.ctx = ctx
Z3_ast_vector_inc_ref(self.ctx.ref(), self.vector)
- def __deepcopy__(self, memo={}):
- return AstVector(self.vector, self.ctx)
-
def __del__(self):
if self.vector is not None and self.ctx.ref() is not None:
Z3_ast_vector_dec_ref(self.ctx.ref(), self.vector)
@@ -5558,8 +5834,13 @@ class AstVector(Z3PPObject):
return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx)
elif isinstance(i, slice):
- return [_to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, ii), self.ctx) for ii in range(*i.indices(self.__len__()))]
-
+ result = []
+ for ii in range(*i.indices(self.__len__())):
+ result.append(_to_ast_ref(
+ Z3_ast_vector_get(self.ctx.ref(), self.vector, ii),
+ self.ctx,
+ ))
+ return result
def __setitem__(self, i, v):
"""Update AST at position `i`.
@@ -5636,7 +5917,10 @@ class AstVector(Z3PPObject):
>>> B
[x]
"""
- return AstVector(Z3_ast_vector_translate(self.ctx.ref(), self.vector, other_ctx.ref()), other_ctx)
+ return AstVector(
+ Z3_ast_vector_translate(self.ctx.ref(), self.vector, other_ctx.ref()),
+ ctx=other_ctx,
+ )
def __copy__(self):
return self.translate(self.ctx)
@@ -5656,6 +5940,8 @@ class AstVector(Z3PPObject):
# AST Map
#
#########################################
+
+
class AstMap:
"""A mapping from ASTs to ASTs."""
@@ -5667,7 +5953,7 @@ class AstMap:
else:
self.map = m
assert ctx is not None
- self.ctx = ctx
+ self.ctx = ctx
Z3_ast_map_inc_ref(self.ctx.ref(), self.map)
def __deepcopy__(self, memo={}):
@@ -5780,12 +6066,13 @@ class AstMap:
#
#########################################
+
class FuncEntry:
"""Store the value of the interpretation of a function in a particular point."""
def __init__(self, entry, ctx):
self.entry = entry
- self.ctx = ctx
+ self.ctx = ctx
Z3_func_entry_inc_ref(self.ctx.ref(), self.entry)
def __deepcopy__(self, memo={}):
@@ -5793,7 +6080,7 @@ class FuncEntry:
def __del__(self):
if self.ctx.ref() is not None:
- Z3_func_entry_dec_ref(self.ctx.ref(), self.entry)
+ Z3_func_entry_dec_ref(self.ctx.ref(), self.entry)
def num_args(self):
"""Return the number of arguments in the given entry.
@@ -5881,25 +6168,23 @@ class FuncEntry:
>>> e.as_list()
[1, 2, 20]
"""
- args = [ self.arg_value(i) for i in range(self.num_args())]
+ args = [self.arg_value(i) for i in range(self.num_args())]
args.append(self.value())
return args
def __repr__(self):
return repr(self.as_list())
+
class FuncInterp(Z3PPObject):
"""Stores the interpretation of a function in a Z3 model."""
def __init__(self, f, ctx):
- self.f = f
+ self.f = f
self.ctx = ctx
if self.f is not None:
Z3_func_interp_inc_ref(self.ctx.ref(), self.f)
- def __deepcopy__(self, memo={}):
- return FuncInterp(self.f, self.ctx)
-
def __del__(self):
if self.f is not None and self.ctx.ref() is not None:
Z3_func_interp_dec_ref(self.ctx.ref(), self.f)
@@ -6001,25 +6286,26 @@ class FuncInterp(Z3PPObject):
>>> m[f].as_list()
[[2, 0], 1]
"""
- r = [ self.entry(i).as_list() for i in range(self.num_entries())]
+ r = [self.entry(i).as_list() for i in range(self.num_entries())]
r.append(self.else_value())
return r
def __repr__(self):
return obj_to_string(self)
+
class ModelRef(Z3PPObject):
"""Model/Solution of a satisfiability problem (aka system of constraints)."""
def __init__(self, m, ctx):
assert ctx is not None
self.model = m
- self.ctx = ctx
+ self.ctx = ctx
Z3_model_inc_ref(self.ctx.ref(), self.model)
def __del__(self):
if self.ctx.ref() is not None:
- Z3_model_dec_ref(self.ctx.ref(), self.model)
+ Z3_model_dec_ref(self.ctx.ref(), self.model)
def __repr__(self):
return obj_to_string(self)
@@ -6029,7 +6315,9 @@ class ModelRef(Z3PPObject):
return Z3_model_to_string(self.ctx.ref(), self.model)
def eval(self, t, model_completion=False):
- """Evaluate the expression `t` in the model `self`. If `model_completion` is enabled, then a default interpretation is automatically added for symbols that do not have an interpretation in the model `self`.
+ """Evaluate the expression `t` in the model `self`.
+ If `model_completion` is enabled, then a default interpretation is automatically added
+ for symbols that do not have an interpretation in the model `self`.
>>> x = Int('x')
>>> s = Solver()
@@ -6096,7 +6384,9 @@ class ModelRef(Z3PPObject):
>>> len(m)
2
"""
- return int(Z3_model_get_num_consts(self.ctx.ref(), self.model)) + int(Z3_model_get_num_funcs(self.ctx.ref(), self.model))
+ num_consts = int(Z3_model_get_num_consts(self.ctx.ref(), self.model))
+ num_funcs = int(Z3_model_get_num_funcs(self.ctx.ref(), self.model))
+ return num_consts + num_funcs
def get_interp(self, decl):
"""Return the interpretation for a given declaration or constant.
@@ -6185,7 +6475,7 @@ class ModelRef(Z3PPObject):
>>> m.sorts()
[A, B]
"""
- return [ self.get_sort(i) for i in range(self.num_sorts()) ]
+ return [self.get_sort(i) for i in range(self.num_sorts())]
def get_universe(self, s):
"""Return the interpretation for the uninterpreted sort `s` in the model `self`.
@@ -6198,7 +6488,7 @@ class ModelRef(Z3PPObject):
sat
>>> m = s.model()
>>> m.get_universe(A)
- [A!val!0, A!val!1]
+ [A!val!1, A!val!0]
"""
if z3_debug():
_z3_assert(isinstance(s, SortRef), "Z3 sort expected")
@@ -6208,7 +6498,8 @@ class ModelRef(Z3PPObject):
return None
def __getitem__(self, idx):
- """If `idx` is an integer, then the declaration at position `idx` in the model `self` is returned. If `idx` is a declaration, then the actual interpretation is returned.
+ """If `idx` is an integer, then the declaration at position `idx` in the model `self` is returned.
+ If `idx` is a declaration, then the actual interpretation is returned.
The elements can be retrieved using position or the actual declaration.
@@ -6285,14 +6576,16 @@ class ModelRef(Z3PPObject):
return self.translate(self.ctx)
-def Model(ctx = None):
+def Model(ctx=None):
ctx = _get_ctx(ctx)
return ModelRef(Z3_mk_model(ctx.ref()), ctx)
+
def is_as_array(n):
"""Return true if n is a Z3 expression of the form (_ as-array f)."""
return isinstance(n, ExprRef) and Z3_is_as_array(n.ctx.ref(), n.as_ast())
+
def get_as_array_func(n):
"""Return the function declaration f associated with a Z3 expression of the form (_ as-array f)."""
if z3_debug():
@@ -6304,12 +6597,14 @@ def get_as_array_func(n):
# Statistics
#
#########################################
+
+
class Statistics:
"""Statistics for `Solver.check()`."""
def __init__(self, stats, ctx):
self.stats = stats
- self.ctx = ctx
+ self.ctx = ctx
Z3_stats_inc_ref(self.ctx.ref(), self.stats)
def __deepcopy__(self, memo={}):
@@ -6317,7 +6612,7 @@ class Statistics:
def __del__(self):
if self.ctx.ref() is not None:
- Z3_stats_dec_ref(self.ctx.ref(), self.stats)
+ Z3_stats_dec_ref(self.ctx.ref(), self.stats)
def __repr__(self):
if in_html_mode():
@@ -6329,10 +6624,10 @@ class Statistics:
out.write(u('
'))
even = False
else:
- out.write(u(' '))
+ out.write(u(" "))
even = True
- out.write(u('%s %s ' % (k, v)))
- out.write(u(''))
+ out.write(u("%s %s " % (k, v)))
+ out.write(u(""))
return out.getvalue()
else:
return Z3_stats_to_string(self.ctx.ref(), self.stats)
@@ -6424,7 +6719,7 @@ class Statistics:
>>> st.nlsat_stages
2
"""
- key = name.replace('_', ' ')
+ key = name.replace("_", " ")
try:
return self.get_key_value(key)
except Z3Exception:
@@ -6435,6 +6730,8 @@ class Statistics:
# Solver
#
#########################################
+
+
class CheckSatResult:
"""Represents the result of a satisfiability check: sat, unsat, unknown.
@@ -6481,16 +6778,21 @@ class CheckSatResult:
set_html_mode(in_html)
return res
-sat = CheckSatResult(Z3_L_TRUE)
-unsat = CheckSatResult(Z3_L_FALSE)
+
+sat = CheckSatResult(Z3_L_TRUE)
+unsat = CheckSatResult(Z3_L_FALSE)
unknown = CheckSatResult(Z3_L_UNDEF)
+
class Solver(Z3PPObject):
- """Solver API provides methods for implementing the main SMT 2.0 commands: push, pop, check, get-model, etc."""
+ """
+ Solver API provides methods for implementing the main SMT 2.0 commands:
+ push, pop, check, get-model, etc.
+ """
def __init__(self, solver=None, ctx=None, logFile=None):
assert solver is None or ctx is not None
- self.ctx = _get_ctx(ctx)
+ self.ctx = _get_ctx(ctx)
self.backtrack_level = 4000000000
self.solver = None
if solver is None:
@@ -6506,7 +6808,8 @@ class Solver(Z3PPObject):
Z3_solver_dec_ref(self.ctx.ref(), self.solver)
def set(self, *args, **keys):
- """Set a configuration option. The method `help()` return a string containing all available options.
+ """Set a configuration option.
+ The method `help()` return a string containing all available options.
>>> s = Solver()
>>> # The option MBQI can be set using three different approaches.
@@ -6540,7 +6843,7 @@ class Solver(Z3PPObject):
Z3_solver_push(self.ctx.ref(), self.solver)
def pop(self, num=1):
- """Backtrack \c num backtracking points.
+ """Backtrack \\c num backtracking points.
>>> x = Int('x')
>>> s = Solver()
@@ -6603,7 +6906,7 @@ class Solver(Z3PPObject):
[x > 0, x < 2]
"""
args = _get_args(args)
- s = BoolSort(self.ctx)
+ s = BoolSort(self.ctx)
for arg in args:
if isinstance(arg, Goal) or isinstance(arg, AstVector):
for f in arg:
@@ -6786,9 +7089,10 @@ class Solver(Z3PPObject):
_z3_assert(isinstance(assumptions, AstVector), "ast vector expected")
_z3_assert(isinstance(variables, AstVector), "ast vector expected")
consequences = AstVector(None, self.ctx)
- r = Z3_solver_get_consequences(self.ctx.ref(), self.solver, assumptions.vector, variables.vector, consequences.vector)
+ r = Z3_solver_get_consequences(self.ctx.ref(), self.solver, assumptions.vector,
+ variables.vector, consequences.vector)
sz = len(consequences)
- consequences = [ consequences[i] for i in range(sz) ]
+ consequences = [consequences[i] for i in range(sz)]
return CheckSatResult(r), consequences
def from_file(self, filename):
@@ -6799,7 +7103,7 @@ class Solver(Z3PPObject):
"""Parse assertions from a string"""
Z3_solver_from_string(self.ctx.ref(), self.solver, s)
- def cube(self, vars = None):
+ def cube(self, vars=None):
"""Get set of cubes
The method takes an optional set of variables that restrict which
variables may be used as a starting point for cubing.
@@ -6808,8 +7112,8 @@ class Solver(Z3PPObject):
"""
self.cube_vs = AstVector(None, self.ctx)
if vars is not None:
- for v in vars:
- self.cube_vs.push(v)
+ for v in vars:
+ self.cube_vs.push(v)
while True:
lvl = self.backtrack_level
self.backtrack_level = 4000000000
@@ -6931,7 +7235,8 @@ class Solver(Z3PPObject):
return self.translate(self.ctx)
def sexpr(self):
- """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
+ """Return a formatted string (in Lisp-like format) with all added constraints.
+ We say the string is in s-expression format.
>>> x = Int('x')
>>> s = Solver()
@@ -6959,7 +7264,10 @@ class Solver(Z3PPObject):
e = es[sz1].as_ast()
else:
e = BoolVal(True, self.ctx).as_ast()
- return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e)
+ return Z3_benchmark_to_smtlib_string(
+ self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e,
+ )
+
def SolverFor(logic, ctx=None, logFile=None):
"""Create a solver customized for the given logic.
@@ -6981,6 +7289,7 @@ def SolverFor(logic, ctx=None, logFile=None):
logic = to_symbol(logic)
return Solver(Z3_mk_solver_for_logic(ctx.ref(), logic), ctx, logFile)
+
def SimpleSolver(ctx=None, logFile=None):
"""Return a simple general purpose solver with limited amount of preprocessing.
@@ -6999,12 +7308,13 @@ def SimpleSolver(ctx=None, logFile=None):
#
#########################################
+
class Fixedpoint(Z3PPObject):
"""Fixedpoint API provides methods for solving with recursive predicates"""
def __init__(self, fixedpoint=None, ctx=None):
assert fixedpoint is None or ctx is not None
- self.ctx = _get_ctx(ctx)
+ self.ctx = _get_ctx(ctx)
self.fixedpoint = None
if fixedpoint is None:
self.fixedpoint = Z3_mk_fixedpoint(self.ctx.ref())
@@ -7037,7 +7347,7 @@ class Fixedpoint(Z3PPObject):
def assert_exprs(self, *args):
"""Assert constraints as background axioms for the fixedpoint solver."""
args = _get_args(args)
- s = BoolSort(self.ctx)
+ s = BoolSort(self.ctx)
for arg in args:
if isinstance(arg, Goal) or isinstance(arg, AstVector):
for f in arg:
@@ -7064,7 +7374,7 @@ class Fixedpoint(Z3PPObject):
"""Assert constraints as background axioms for the fixedpoint solver. Alias for assert_expr."""
self.assert_exprs(*args)
- def add_rule(self, head, body = None, name = None):
+ def add_rule(self, head, body=None, name=None):
"""Assert rules defining recursive predicates to the fixedpoint solver.
>>> a = Bool('a')
>>> b = Bool('b')
@@ -7084,14 +7394,14 @@ class Fixedpoint(Z3PPObject):
Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name)
else:
body = _get_args(body)
- f = self.abstract(Implies(And(body, self.ctx),head))
+ f = self.abstract(Implies(And(body, self.ctx), head))
Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
- def rule(self, head, body = None, name = None):
+ def rule(self, head, body=None, name=None):
"""Assert rules defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
self.add_rule(head, body, name)
- def fact(self, head, name = None):
+ def fact(self, head, name=None):
"""Assert facts defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
self.add_rule(head, None, name)
@@ -7117,20 +7427,20 @@ class Fixedpoint(Z3PPObject):
r = Z3_fixedpoint_query(self.ctx.ref(), self.fixedpoint, query.as_ast())
return CheckSatResult(r)
- def query_from_lvl (self, lvl, *query):
+ def query_from_lvl(self, lvl, *query):
"""Query the fixedpoint engine whether formula is derivable starting at the given query level.
"""
query = _get_args(query)
sz = len(query)
if sz >= 1 and isinstance(query[0], FuncDecl):
- _z3_assert (False, "unsupported")
+ _z3_assert(False, "unsupported")
else:
if sz == 1:
query = query[0]
else:
query = And(query)
query = self.abstract(query, False)
- r = Z3_fixedpoint_query_from_lvl (self.ctx.ref(), self.fixedpoint, query.as_ast(), lvl)
+ r = Z3_fixedpoint_query_from_lvl(self.ctx.ref(), self.fixedpoint, query.as_ast(), lvl)
return CheckSatResult(r)
def update_rule(self, head, body, name):
@@ -7139,7 +7449,7 @@ class Fixedpoint(Z3PPObject):
name = ""
name = to_symbol(name, self.ctx)
body = _get_args(body)
- f = self.abstract(Implies(And(body, self.ctx),head))
+ f = self.abstract(Implies(And(body, self.ctx), head))
Z3_fixedpoint_update_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
def get_answer(self):
@@ -7160,21 +7470,25 @@ class Fixedpoint(Z3PPObject):
"""retrieve rule names along the counterexample trace"""
# this is a hack as I don't know how to return a list of symbols from C++;
# obtain names as a single string separated by semicolons
- names = _symbol2py (self.ctx, Z3_fixedpoint_get_rule_names_along_trace(self.ctx.ref(), self.fixedpoint))
+ names = _symbol2py(self.ctx, Z3_fixedpoint_get_rule_names_along_trace(self.ctx.ref(), self.fixedpoint))
# split into individual names
- return names.split (';')
+ return names.split(";")
def get_num_levels(self, predicate):
"""Retrieve number of levels used for predicate in PDR engine"""
return Z3_fixedpoint_get_num_levels(self.ctx.ref(), self.fixedpoint, predicate.ast)
def get_cover_delta(self, level, predicate):
- """Retrieve properties known about predicate for the level'th unfolding. -1 is treated as the limit (infinity)"""
+ """Retrieve properties known about predicate for the level'th unfolding.
+ -1 is treated as the limit (infinity)
+ """
r = Z3_fixedpoint_get_cover_delta(self.ctx.ref(), self.fixedpoint, level, predicate.ast)
return _to_expr_ref(r, self.ctx)
def add_cover(self, level, predicate, property):
- """Add property to predicate for the level'th unfolding. -1 is treated as infinity (infinity)"""
+ """Add property to predicate for the level'th unfolding.
+ -1 is treated as infinity (infinity)
+ """
Z3_fixedpoint_add_cover(self.ctx.ref(), self.fixedpoint, level, predicate.ast, property.ast)
def register_relation(self, *relations):
@@ -7214,7 +7528,8 @@ class Fixedpoint(Z3PPObject):
return self.sexpr()
def sexpr(self):
- """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
+ """Return a formatted string (in Lisp-like format) with all added constraints.
+ We say the string is in s-expression format.
"""
return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, 0, (Ast * 0)())
@@ -7271,6 +7586,7 @@ class FiniteDomainSortRef(SortRef):
else:
raise Z3Exception("Failed to retrieve finite domain sort size")
+
def FiniteDomainSort(name, sz, ctx=None):
"""Create a named finite domain sort of a given size sz"""
if not isinstance(name, Symbol):
@@ -7278,6 +7594,7 @@ def FiniteDomainSort(name, sz, ctx=None):
ctx = _get_ctx(ctx)
return FiniteDomainSortRef(Z3_mk_finite_domain_sort(ctx.ref(), name, sz), ctx)
+
def is_finite_domain_sort(s):
"""Return True if `s` is a Z3 finite-domain sort.
@@ -7300,6 +7617,7 @@ class FiniteDomainRef(ExprRef):
"""Return a Z3 floating point expression as a Python string."""
return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
+
def is_finite_domain(a):
"""Return `True` if `a` is a Z3 finite-domain expression.
@@ -7349,10 +7667,11 @@ def FiniteDomainVal(val, sort, ctx=None):
100
"""
if z3_debug():
- _z3_assert(is_finite_domain_sort(sort), "Expected finite-domain sort" )
+ _z3_assert(is_finite_domain_sort(sort), "Expected finite-domain sort")
ctx = sort.ctx
return FiniteDomainNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), sort.ast), ctx)
+
def is_finite_domain_value(a):
"""Return `True` if `a` is a Z3 finite-domain value.
@@ -7407,20 +7726,22 @@ class OptimizeObjective:
return "%s:%s" % (self._value, self._is_max)
-
_on_models = {}
+
def _global_on_model(ctx):
(fn, mdl) = _on_models[ctx]
fn(mdl)
-
+
+
_on_model_eh = on_model_eh_type(_global_on_model)
+
class Optimize(Z3PPObject):
"""Optimize API provides methods for solving using objective functions and weighted soft constraints"""
def __init__(self, ctx=None):
- self.ctx = _get_ctx(ctx)
+ self.ctx = _get_ctx(ctx)
self.optimize = Z3_mk_optimize(self.ctx.ref())
self._on_models_id = None
Z3_optimize_inc_ref(self.ctx.ref(), self.optimize)
@@ -7435,7 +7756,8 @@ class Optimize(Z3PPObject):
del _on_models[self._on_models_id]
def set(self, *args, **keys):
- """Set a configuration option. The method `help()` return a string containing all available options.
+ """Set a configuration option.
+ The method `help()` return a string containing all available options.
"""
p = args2params(args, keys, self.ctx)
Z3_optimize_set_params(self.ctx.ref(), self.optimize, p.params)
@@ -7451,7 +7773,7 @@ class Optimize(Z3PPObject):
def assert_exprs(self, *args):
"""Assert constraints as background axioms for the optimize solver."""
args = _get_args(args)
- s = BoolSort(self.ctx)
+ s = BoolSort(self.ctx)
for arg in args:
if isinstance(arg, Goal) or isinstance(arg, AstVector):
for f in arg:
@@ -7497,7 +7819,7 @@ class Optimize(Z3PPObject):
_z3_assert(isinstance(p, BoolRef) and is_const(p), "Boolean expression expected")
Z3_optimize_assert_and_track(self.ctx.ref(), self.optimize, a.as_ast(), p.as_ast())
- def add_soft(self, arg, weight = "1", id = None):
+ def add_soft(self, arg, weight="1", id=None):
"""Add soft constraint with optional weight and optional identifier.
If no weight is supplied, then the penalty for violating the soft constraint
is 1.
@@ -7513,20 +7835,29 @@ class Optimize(Z3PPObject):
if id is None:
id = ""
id = to_symbol(id, self.ctx)
+
def asoft(a):
v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, a.as_ast(), weight, id)
return OptimizeObjective(self, v, False)
- if sys.version >= '3' and isinstance(arg, Iterable):
+ if sys.version_info.major >= 3 and isinstance(arg, Iterable):
return [asoft(a) for a in arg]
return asoft(arg)
def maximize(self, arg):
"""Add objective function to maximize."""
- return OptimizeObjective(self, Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast()), True)
+ return OptimizeObjective(
+ self,
+ Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast()),
+ is_max=True,
+ )
def minimize(self, arg):
"""Add objective function to minimize."""
- return OptimizeObjective(self, Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast()), False)
+ return OptimizeObjective(
+ self,
+ Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast()),
+ is_max=False,
+ )
def push(self):
"""create a backtracking point for added rules, facts and assertions"""
@@ -7600,7 +7931,8 @@ class Optimize(Z3PPObject):
return self.sexpr()
def sexpr(self):
- """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
+ """Return a formatted string (in Lisp-like format) with all added constraints.
+ We say the string is in s-expression format.
"""
return Z3_optimize_to_string(self.ctx.ref(), self.optimize)
@@ -7615,11 +7947,13 @@ class Optimize(Z3PPObject):
The life-time of the model is limited to the callback so the
model has to be (deep) copied if it is to be used after the callback
"""
- id = len(_on_models) + 41
+ id = len(_on_models) + 41
mdl = Model(self.ctx)
_on_models[id] = (on_model, mdl)
self._on_models_id = id
- Z3_optimize_register_model_eh(self.ctx.ref(), self.optimize, mdl.model, ctypes.c_void_p(id), _on_model_eh)
+ Z3_optimize_register_model_eh(
+ self.ctx.ref(), self.optimize, mdl.model, ctypes.c_void_p(id), _on_model_eh,
+ )
#########################################
@@ -7628,11 +7962,13 @@ class Optimize(Z3PPObject):
#
#########################################
class ApplyResult(Z3PPObject):
- """An ApplyResult object contains the subgoals produced by a tactic when applied to a goal. It also contains model and proof converters."""
+ """An ApplyResult object contains the subgoals produced by a tactic when applied to a goal.
+ It also contains model and proof converters.
+ """
def __init__(self, result, ctx):
self.result = result
- self.ctx = ctx
+ self.ctx = ctx
Z3_apply_result_inc_ref(self.ctx.ref(), self.result)
def __deepcopy__(self, memo={}):
@@ -7685,7 +8021,6 @@ class ApplyResult(Z3PPObject):
"""Return a textual representation of the s-expression representing the set of subgoals in `self`."""
return Z3_apply_result_to_string(self.ctx.ref(), self.result)
-
def as_expr(self):
"""Return a Z3 expression consisting of all subgoals.
@@ -7710,20 +8045,25 @@ class ApplyResult(Z3PPObject):
elif sz == 1:
return self[0].as_expr()
else:
- return Or([ self[i].as_expr() for i in range(len(self)) ])
+ return Or([self[i].as_expr() for i in range(len(self))])
#########################################
#
# Tactics
#
#########################################
-class Tactic:
- """Tactics transform, solver and/or simplify sets of constraints (Goal). A Tactic can be converted into a Solver using the method solver().
- Several combinators are available for creating new tactics using the built-in ones: Then(), OrElse(), FailIf(), Repeat(), When(), Cond().
+
+class Tactic:
+ """Tactics transform, solver and/or simplify sets of constraints (Goal).
+ A Tactic can be converted into a Solver using the method solver().
+
+ Several combinators are available for creating new tactics using the built-in ones:
+ Then(), OrElse(), FailIf(), Repeat(), When(), Cond().
"""
+
def __init__(self, tactic, ctx=None):
- self.ctx = _get_ctx(ctx)
+ self.ctx = _get_ctx(ctx)
self.tactic = None
if isinstance(tactic, TacticObj):
self.tactic = tactic
@@ -7769,7 +8109,7 @@ class Tactic:
[[y >= 1]]
"""
if z3_debug():
- _z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expressions expected")
+ _z3_assert(isinstance(goal, (Goal, BoolRef)), "Z3 Goal or Boolean expressions expected")
goal = _to_goal(goal)
if len(arguments) > 0 or len(keywords) > 0:
p = args2params(arguments, keywords, self.ctx)
@@ -7795,20 +8135,23 @@ class Tactic:
"""Return the parameter description set."""
return ParamDescrsRef(Z3_tactic_get_param_descrs(self.ctx.ref(), self.tactic), self.ctx)
+
def _to_goal(a):
if isinstance(a, BoolRef):
- goal = Goal(ctx = a.ctx)
+ goal = Goal(ctx=a.ctx)
goal.add(a)
return goal
else:
return a
+
def _to_tactic(t, ctx=None):
if isinstance(t, Tactic):
return t
else:
return Tactic(t, ctx)
+
def _and_then(t1, t2, ctx=None):
t1 = _to_tactic(t1, ctx)
t2 = _to_tactic(t2, ctx)
@@ -7816,6 +8159,7 @@ def _and_then(t1, t2, ctx=None):
_z3_assert(t1.ctx == t2.ctx, "Context mismatch")
return Tactic(Z3_tactic_and_then(t1.ctx.ref(), t1.tactic, t2.tactic), t1.ctx)
+
def _or_else(t1, t2, ctx=None):
t1 = _to_tactic(t1, ctx)
t2 = _to_tactic(t2, ctx)
@@ -7823,6 +8167,7 @@ def _or_else(t1, t2, ctx=None):
_z3_assert(t1.ctx == t2.ctx, "Context mismatch")
return Tactic(Z3_tactic_or_else(t1.ctx.ref(), t1.tactic, t2.tactic), t1.ctx)
+
def AndThen(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` in sequence.
@@ -7835,13 +8180,14 @@ def AndThen(*ts, **ks):
"""
if z3_debug():
_z3_assert(len(ts) >= 2, "At least two arguments expected")
- ctx = ks.get('ctx', None)
+ ctx = ks.get("ctx", None)
num = len(ts)
r = ts[0]
for i in range(num - 1):
- r = _and_then(r, ts[i+1], ctx)
+ r = _and_then(r, ts[i + 1], ctx)
return r
+
def Then(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` in sequence. Shorthand for AndThen(*ts, **ks).
@@ -7854,6 +8200,7 @@ def Then(*ts, **ks):
"""
return AndThen(*ts, **ks)
+
def OrElse(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` until one of them succeeds (it doesn't fail).
@@ -7867,13 +8214,14 @@ def OrElse(*ts, **ks):
"""
if z3_debug():
_z3_assert(len(ts) >= 2, "At least two arguments expected")
- ctx = ks.get('ctx', None)
+ ctx = ks.get("ctx", None)
num = len(ts)
r = ts[0]
for i in range(num - 1):
- r = _or_else(r, ts[i+1], ctx)
+ r = _or_else(r, ts[i + 1], ctx)
return r
+
def ParOr(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` in parallel until one of them succeeds (it doesn't fail).
@@ -7884,16 +8232,18 @@ def ParOr(*ts, **ks):
"""
if z3_debug():
_z3_assert(len(ts) >= 2, "At least two arguments expected")
- ctx = _get_ctx(ks.get('ctx', None))
- ts = [ _to_tactic(t, ctx) for t in ts ]
- sz = len(ts)
+ ctx = _get_ctx(ks.get("ctx", None))
+ ts = [_to_tactic(t, ctx) for t in ts]
+ sz = len(ts)
_args = (TacticObj * sz)()
for i in range(sz):
_args[i] = ts[i].tactic
return Tactic(Z3_tactic_par_or(ctx.ref(), sz, _args), ctx)
+
def ParThen(t1, t2, ctx=None):
- """Return a tactic that applies t1 and then t2 to every subgoal produced by t1. The subgoals are processed in parallel.
+ """Return a tactic that applies t1 and then t2 to every subgoal produced by t1.
+ The subgoals are processed in parallel.
>>> x, y = Ints('x y')
>>> t = ParThen(Tactic('split-clause'), Tactic('propagate-values'))
@@ -7906,10 +8256,12 @@ def ParThen(t1, t2, ctx=None):
_z3_assert(t1.ctx == t2.ctx, "Context mismatch")
return Tactic(Z3_tactic_par_and_then(t1.ctx.ref(), t1.tactic, t2.tactic), t1.ctx)
+
def ParAndThen(t1, t2, ctx=None):
"""Alias for ParThen(t1, t2, ctx)."""
return ParThen(t1, t2, ctx)
+
def With(t, *args, **keys):
"""Return a tactic that applies tactic `t` using the given configuration options.
@@ -7918,11 +8270,12 @@ def With(t, *args, **keys):
>>> t((x + 1)*(y + 2) == 0)
[[2*x + y + x*y == -2]]
"""
- ctx = keys.pop('ctx', None)
+ ctx = keys.pop("ctx", None)
t = _to_tactic(t, ctx)
p = args2params(args, keys, t.ctx)
return Tactic(Z3_tactic_using_params(t.ctx.ref(), t.tactic, p.params), t.ctx)
+
def WithParams(t, p):
"""Return a tactic that applies tactic `t` using the given configuration options.
@@ -7936,8 +8289,10 @@ def WithParams(t, p):
t = _to_tactic(t, None)
return Tactic(Z3_tactic_using_params(t.ctx.ref(), t.tactic, p.params), t.ctx)
+
def Repeat(t, max=4294967295, ctx=None):
- """Return a tactic that keeps applying `t` until the goal is not modified anymore or the maximum number of iterations `max` is reached.
+ """Return a tactic that keeps applying `t` until the goal is not modified anymore
+ or the maximum number of iterations `max` is reached.
>>> x, y = Ints('x y')
>>> c = And(Or(x == 0, x == 1), Or(y == 0, y == 1), x > y)
@@ -7955,6 +8310,7 @@ def Repeat(t, max=4294967295, ctx=None):
t = _to_tactic(t, ctx)
return Tactic(Z3_tactic_repeat(t.ctx.ref(), t.tactic, max), t.ctx)
+
def TryFor(t, ms, ctx=None):
"""Return a tactic that applies `t` to a given goal for `ms` milliseconds.
@@ -7963,6 +8319,7 @@ def TryFor(t, ms, ctx=None):
t = _to_tactic(t, ctx)
return Tactic(Z3_tactic_try_for(t.ctx.ref(), t.tactic, ms), t.ctx)
+
def tactics(ctx=None):
"""Return a list of all available tactics in Z3.
@@ -7971,7 +8328,8 @@ def tactics(ctx=None):
True
"""
ctx = _get_ctx(ctx)
- return [ Z3_get_tactic_name(ctx.ref(), i) for i in range(Z3_get_num_tactics(ctx.ref())) ]
+ return [Z3_get_tactic_name(ctx.ref(), i) for i in range(Z3_get_num_tactics(ctx.ref()))]
+
def tactic_description(name, ctx=None):
"""Return a short description for the tactic named `name`.
@@ -7981,6 +8339,7 @@ def tactic_description(name, ctx=None):
ctx = _get_ctx(ctx)
return Z3_tactic_get_descr(ctx.ref(), name)
+
def describe_tactics():
"""Display a (tabular) description of all available tactics in Z3."""
if in_html_mode():
@@ -7991,19 +8350,23 @@ def describe_tactics():
print('')
even = False
else:
- print(' ')
+ print(" ")
even = True
- print('%s %s ' % (t, insert_line_breaks(tactic_description(t), 40)))
- print('')
+ print("%s %s " % (t, insert_line_breaks(tactic_description(t), 40)))
+ print("")
else:
for t in tactics():
- print('%s : %s' % (t, tactic_description(t)))
+ print("%s : %s" % (t, tactic_description(t)))
+
class Probe:
- """Probes are used to inspect a goal (aka problem) and collect information that may be used to decide which solver and/or preprocessing step will be used."""
+ """Probes are used to inspect a goal (aka problem) and collect information that may be used
+ to decide which solver and/or preprocessing step will be used.
+ """
+
def __init__(self, probe, ctx=None):
- self.ctx = _get_ctx(ctx)
- self.probe = None
+ self.ctx = _get_ctx(ctx)
+ self.probe = None
if isinstance(probe, ProbeObj):
self.probe = probe
elif isinstance(probe, float):
@@ -8032,7 +8395,8 @@ class Probe:
Z3_probe_dec_ref(self.ctx.ref(), self.probe)
def __lt__(self, other):
- """Return a probe that evaluates to "true" when the value returned by `self` is less than the value returned by `other`.
+ """Return a probe that evaluates to "true" when the value returned by `self`
+ is less than the value returned by `other`.
>>> p = Probe('size') < 10
>>> x = Int('x')
@@ -8045,7 +8409,8 @@ class Probe:
return Probe(Z3_probe_lt(self.ctx.ref(), self.probe, _to_probe(other, self.ctx).probe), self.ctx)
def __gt__(self, other):
- """Return a probe that evaluates to "true" when the value returned by `self` is greater than the value returned by `other`.
+ """Return a probe that evaluates to "true" when the value returned by `self`
+ is greater than the value returned by `other`.
>>> p = Probe('size') > 10
>>> x = Int('x')
@@ -8058,7 +8423,8 @@ class Probe:
return Probe(Z3_probe_gt(self.ctx.ref(), self.probe, _to_probe(other, self.ctx).probe), self.ctx)
def __le__(self, other):
- """Return a probe that evaluates to "true" when the value returned by `self` is less than or equal to the value returned by `other`.
+ """Return a probe that evaluates to "true" when the value returned by `self`
+ is less than or equal to the value returned by `other`.
>>> p = Probe('size') <= 2
>>> x = Int('x')
@@ -8071,7 +8437,8 @@ class Probe:
return Probe(Z3_probe_le(self.ctx.ref(), self.probe, _to_probe(other, self.ctx).probe), self.ctx)
def __ge__(self, other):
- """Return a probe that evaluates to "true" when the value returned by `self` is greater than or equal to the value returned by `other`.
+ """Return a probe that evaluates to "true" when the value returned by `self`
+ is greater than or equal to the value returned by `other`.
>>> p = Probe('size') >= 2
>>> x = Int('x')
@@ -8084,7 +8451,8 @@ class Probe:
return Probe(Z3_probe_ge(self.ctx.ref(), self.probe, _to_probe(other, self.ctx).probe), self.ctx)
def __eq__(self, other):
- """Return a probe that evaluates to "true" when the value returned by `self` is equal to the value returned by `other`.
+ """Return a probe that evaluates to "true" when the value returned by `self`
+ is equal to the value returned by `other`.
>>> p = Probe('size') == 2
>>> x = Int('x')
@@ -8097,7 +8465,8 @@ class Probe:
return Probe(Z3_probe_eq(self.ctx.ref(), self.probe, _to_probe(other, self.ctx).probe), self.ctx)
def __ne__(self, other):
- """Return a probe that evaluates to "true" when the value returned by `self` is not equal to the value returned by `other`.
+ """Return a probe that evaluates to "true" when the value returned by `self`
+ is not equal to the value returned by `other`.
>>> p = Probe('size') != 2
>>> x = Int('x')
@@ -8134,10 +8503,11 @@ class Probe:
1.0
"""
if z3_debug():
- _z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expression expected")
+ _z3_assert(isinstance(goal, (Goal, BoolRef)), "Z3 Goal or Boolean expression expected")
goal = _to_goal(goal)
return Z3_probe_apply(self.ctx.ref(), self.probe, goal.goal)
+
def is_probe(p):
"""Return `True` if `p` is a Z3 probe.
@@ -8148,12 +8518,14 @@ def is_probe(p):
"""
return isinstance(p, Probe)
+
def _to_probe(p, ctx=None):
if is_probe(p):
return p
else:
return Probe(p, ctx)
+
def probes(ctx=None):
"""Return a list of all available probes in Z3.
@@ -8162,7 +8534,8 @@ def probes(ctx=None):
True
"""
ctx = _get_ctx(ctx)
- return [ Z3_get_probe_name(ctx.ref(), i) for i in range(Z3_get_num_probes(ctx.ref())) ]
+ return [Z3_get_probe_name(ctx.ref(), i) for i in range(Z3_get_num_probes(ctx.ref()))]
+
def probe_description(name, ctx=None):
"""Return a short description for the probe named `name`.
@@ -8172,6 +8545,7 @@ def probe_description(name, ctx=None):
ctx = _get_ctx(ctx)
return Z3_probe_get_descr(ctx.ref(), name)
+
def describe_probes():
"""Display a (tabular) description of all available probes in Z3."""
if in_html_mode():
@@ -8182,13 +8556,14 @@ def describe_probes():
print('')
even = False
else:
- print(' ')
+ print(" ")
even = True
- print('%s %s ' % (p, insert_line_breaks(probe_description(p), 40)))
- print('')
+ print("%s %s " % (p, insert_line_breaks(probe_description(p), 40)))
+ print("")
else:
for p in probes():
- print('%s : %s' % (p, probe_description(p)))
+ print("%s : %s" % (p, probe_description(p)))
+
def _probe_nary(f, args, ctx):
if z3_debug():
@@ -8196,19 +8571,24 @@ def _probe_nary(f, args, ctx):
num = len(args)
r = _to_probe(args[0], ctx)
for i in range(num - 1):
- r = Probe(f(ctx.ref(), r.probe, _to_probe(args[i+1], ctx).probe), ctx)
+ r = Probe(f(ctx.ref(), r.probe, _to_probe(args[i + 1], ctx).probe), ctx)
return r
+
def _probe_and(args, ctx):
return _probe_nary(Z3_probe_and, args, ctx)
+
def _probe_or(args, ctx):
return _probe_nary(Z3_probe_or, args, ctx)
-def FailIf(p, ctx=None):
- """Return a tactic that fails if the probe `p` evaluates to true. Otherwise, it returns the input goal unmodified.
- In the following example, the tactic applies 'simplify' if and only if there are more than 2 constraints in the goal.
+def FailIf(p, ctx=None):
+ """Return a tactic that fails if the probe `p` evaluates to true.
+ Otherwise, it returns the input goal unmodified.
+
+ In the following example, the tactic applies 'simplify' if and only if there are
+ more than 2 constraints in the goal.
>>> t = OrElse(FailIf(Probe('size') > 2), Tactic('simplify'))
>>> x, y = Ints('x y')
@@ -8224,8 +8604,10 @@ def FailIf(p, ctx=None):
p = _to_probe(p, ctx)
return Tactic(Z3_tactic_fail_if(p.ctx.ref(), p.probe), p.ctx)
+
def When(p, t, ctx=None):
- """Return a tactic that applies tactic `t` only if probe `p` evaluates to true. Otherwise, it returns the input goal unmodified.
+ """Return a tactic that applies tactic `t` only if probe `p` evaluates to true.
+ Otherwise, it returns the input goal unmodified.
>>> t = When(Probe('size') > 2, Tactic('simplify'))
>>> x, y = Ints('x y')
@@ -8242,6 +8624,7 @@ def When(p, t, ctx=None):
t = _to_tactic(t, ctx)
return Tactic(Z3_tactic_when(t.ctx.ref(), p.probe, t.tactic), t.ctx)
+
def Cond(p, t1, t2, ctx=None):
"""Return a tactic that applies tactic `t1` to a goal if probe `p` evaluates to true, and `t2` otherwise.
@@ -8258,6 +8641,7 @@ def Cond(p, t1, t2, ctx=None):
#
#########################################
+
def simplify(a, *arguments, **keywords):
"""Simplify the expression `a` using the given options.
@@ -8282,16 +8666,20 @@ def simplify(a, *arguments, **keywords):
else:
return _to_expr_ref(Z3_simplify(a.ctx_ref(), a.as_ast()), a.ctx)
+
def help_simplify():
"""Return a string describing all options available for Z3 `simplify` procedure."""
print(Z3_simplify_get_help(main_ctx().ref()))
+
def simplify_param_descrs():
"""Return the set of parameter descriptions for Z3 `simplify` procedure."""
return ParamDescrsRef(Z3_simplify_get_param_descrs(main_ctx().ref()), main_ctx())
+
def substitute(t, *m):
- """Apply substitution m on t, m is a list of pairs of the form (from, to). Every occurrence in t of from is replaced with to.
+ """Apply substitution m on t, m is a list of pairs of the form (from, to).
+ Every occurrence in t of from is replaced with to.
>>> x = Int('x')
>>> y = Int('y')
@@ -8307,15 +8695,17 @@ def substitute(t, *m):
m = m1
if z3_debug():
_z3_assert(is_expr(t), "Z3 expression expected")
- _z3_assert(all([isinstance(p, tuple) and is_expr(p[0]) and is_expr(p[1]) and p[0].sort().eq(p[1].sort()) for p in m]), "Z3 invalid substitution, expression pairs expected.")
+ _z3_assert(all([isinstance(p, tuple) and is_expr(p[0]) and is_expr(p[1]) and p[0].sort().eq(
+ p[1].sort()) for p in m]), "Z3 invalid substitution, expression pairs expected.")
num = len(m)
_from = (Ast * num)()
- _to = (Ast * num)()
+ _to = (Ast * num)()
for i in range(num):
_from[i] = m[i][0].as_ast()
- _to[i] = m[i][1].as_ast()
+ _to[i] = m[i][1].as_ast()
return _to_expr_ref(Z3_substitute(t.ctx.ref(), t.as_ast(), num, _from, _to), t.ctx)
+
def substitute_vars(t, *m):
"""Substitute the free variables in t with the expression in m.
@@ -8331,11 +8721,12 @@ def substitute_vars(t, *m):
_z3_assert(is_expr(t), "Z3 expression expected")
_z3_assert(all([is_expr(n) for n in m]), "Z3 invalid substitution, list of expressions expected.")
num = len(m)
- _to = (Ast * num)()
+ _to = (Ast * num)()
for i in range(num):
_to[i] = m[i].as_ast()
return _to_expr_ref(Z3_substitute_vars(t.ctx.ref(), t.as_ast(), num, _to), t.ctx)
+
def Sum(*args):
"""Create the sum of the Z3 expressions.
@@ -8348,13 +8739,13 @@ def Sum(*args):
>>> Sum(A)
a__0 + a__1 + a__2 + a__3 + a__4
"""
- args = _get_args(args)
+ args = _get_args(args)
if len(args) == 0:
return 0
- ctx = _ctx_from_ast_arg_list(args)
+ ctx = _ctx_from_ast_arg_list(args)
if ctx is None:
return _reduce(lambda a, b: a + b, args, 0)
- args = _coerce_expr_list(args, ctx)
+ args = _coerce_expr_list(args, ctx)
if is_bv(args[0]):
return _reduce(lambda a, b: a + b, args, 0)
else:
@@ -8374,29 +8765,30 @@ def Product(*args):
>>> Product(A)
a__0*a__1*a__2*a__3*a__4
"""
- args = _get_args(args)
+ args = _get_args(args)
if len(args) == 0:
return 1
- ctx = _ctx_from_ast_arg_list(args)
+ ctx = _ctx_from_ast_arg_list(args)
if ctx is None:
return _reduce(lambda a, b: a * b, args, 1)
- args = _coerce_expr_list(args, ctx)
+ args = _coerce_expr_list(args, ctx)
if is_bv(args[0]):
return _reduce(lambda a, b: a * b, args, 1)
else:
_args, sz = _to_ast_array(args)
return ArithRef(Z3_mk_mul(ctx.ref(), sz, _args), ctx)
+
def AtMost(*args):
"""Create an at-most Pseudo-Boolean k constraint.
>>> a, b, c = Bools('a b c')
>>> f = AtMost(a, b, c, 2)
"""
- args = _get_args(args)
+ args = _get_args(args)
if z3_debug():
_z3_assert(len(args) > 1, "Non empty list of arguments expected")
- ctx = _ctx_from_ast_arg_list(args)
+ ctx = _ctx_from_ast_arg_list(args)
if z3_debug():
_z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression")
args1 = _coerce_expr_list(args[:-1], ctx)
@@ -8404,16 +8796,17 @@ def AtMost(*args):
_args, sz = _to_ast_array(args1)
return BoolRef(Z3_mk_atmost(ctx.ref(), sz, _args, k), ctx)
+
def AtLeast(*args):
"""Create an at-most Pseudo-Boolean k constraint.
>>> a, b, c = Bools('a b c')
>>> f = AtLeast(a, b, c, 2)
"""
- args = _get_args(args)
+ args = _get_args(args)
if z3_debug():
_z3_assert(len(args) > 1, "Non empty list of arguments expected")
- ctx = _ctx_from_ast_arg_list(args)
+ ctx = _ctx_from_ast_arg_list(args)
if z3_debug():
_z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression")
args1 = _coerce_expr_list(args[:-1], ctx)
@@ -8421,21 +8814,23 @@ def AtLeast(*args):
_args, sz = _to_ast_array(args1)
return BoolRef(Z3_mk_atleast(ctx.ref(), sz, _args, k), ctx)
+
def _reorder_pb_arg(arg):
a, b = arg
if not _is_int(b) and _is_int(a):
return b, a
return arg
-def _pb_args_coeffs(args, default_ctx = None):
- args = _get_args_ast_list(args)
+
+def _pb_args_coeffs(args, default_ctx=None):
+ args = _get_args_ast_list(args)
if len(args) == 0:
- return _get_ctx(default_ctx), 0, (Ast * 0)(), (ctypes.c_int * 0)()
+ return _get_ctx(default_ctx), 0, (Ast * 0)(), (ctypes.c_int * 0)()
args = [_reorder_pb_arg(arg) for arg in args]
args, coeffs = zip(*args)
if z3_debug():
_z3_assert(len(args) > 0, "Non empty list of arguments expected")
- ctx = _ctx_from_ast_arg_list(args)
+ ctx = _ctx_from_ast_arg_list(args)
if z3_debug():
_z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression")
args = _coerce_expr_list(args, ctx)
@@ -8446,6 +8841,7 @@ def _pb_args_coeffs(args, default_ctx = None):
_coeffs[i] = coeffs[i]
return ctx, sz, _args, _coeffs
+
def PbLe(args, k):
"""Create a Pseudo-Boolean inequality k constraint.
@@ -8456,6 +8852,7 @@ def PbLe(args, k):
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx)
+
def PbGe(args, k):
"""Create a Pseudo-Boolean inequality k constraint.
@@ -8466,7 +8863,8 @@ def PbGe(args, k):
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx)
-def PbEq(args, k, ctx = None):
+
+def PbEq(args, k, ctx=None):
"""Create a Pseudo-Boolean inequality k constraint.
>>> a, b, c = Bools('a b c')
@@ -8506,6 +8904,7 @@ def solve(*args, **keywords):
else:
print(s.model())
+
def solve_using(s, *args, **keywords):
"""Solve the constraints `*args` using solver `s`.
@@ -8536,6 +8935,7 @@ def solve_using(s, *args, **keywords):
print("Solution:")
print(s.model())
+
def prove(claim, show=False, **keywords):
"""Try to prove the given claim.
@@ -8563,6 +8963,7 @@ def prove(claim, show=False, **keywords):
print("counterexample")
print(s.model())
+
def _solve_html(*args, **keywords):
"""Version of function `solve` used in RiSE4Fun."""
show = keywords.pop("show", False)
@@ -8586,6 +8987,7 @@ def _solve_html(*args, **keywords):
print("Solution: ")
print(s.model())
+
def _solve_using_html(s, *args, **keywords):
"""Version of function `solve_using` used in RiSE4Fun."""
show = keywords.pop("show", False)
@@ -8610,6 +9012,7 @@ def _solve_using_html(s, *args, **keywords):
print("Solution: ")
print(s.model())
+
def _prove_html(claim, show=False, **keywords):
"""Version of function `prove` used in RiSE4Fun."""
if z3_debug():
@@ -8629,10 +9032,11 @@ def _prove_html(claim, show=False, **keywords):
print("counterexample ")
print(s.model())
+
def _dict2sarray(sorts, ctx):
sz = len(sorts)
_names = (Symbol * sz)()
- _sorts = (Sort * sz) ()
+ _sorts = (Sort * sz)()
i = 0
for k in sorts:
v = sorts[k]
@@ -8644,10 +9048,11 @@ def _dict2sarray(sorts, ctx):
i = i + 1
return sz, _names, _sorts
+
def _dict2darray(decls, ctx):
sz = len(decls)
_names = (Symbol * sz)()
- _decls = (FuncDecl * sz) ()
+ _decls = (FuncDecl * sz)()
i = 0
for k in decls:
v = decls[k]
@@ -8683,6 +9088,7 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None):
dsz, dnames, ddecls = _dict2darray(decls, ctx)
return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx)
+
def parse_smt2_file(f, sorts={}, decls={}, ctx=None):
"""Parse a file in SMT 2.0 format using the given sorts and decls.
@@ -8706,6 +9112,7 @@ _dflt_rounding_mode = Z3_OP_FPA_RM_TOWARD_ZERO
_dflt_fpsort_ebits = 11
_dflt_fpsort_sbits = 53
+
def get_default_rounding_mode(ctx=None):
"""Retrieves the global default rounding mode."""
global _dflt_rounding_mode
@@ -8720,34 +9127,44 @@ def get_default_rounding_mode(ctx=None):
elif _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY:
return RNA(ctx)
+
+_ROUNDING_MODES = frozenset({
+ Z3_OP_FPA_RM_TOWARD_ZERO,
+ Z3_OP_FPA_RM_TOWARD_NEGATIVE,
+ Z3_OP_FPA_RM_TOWARD_POSITIVE,
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN,
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY
+})
+
+
def set_default_rounding_mode(rm, ctx=None):
global _dflt_rounding_mode
if is_fprm_value(rm):
_dflt_rounding_mode = rm.decl().kind()
else:
- _z3_assert(_dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_ZERO or
- _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_NEGATIVE or
- _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_POSITIVE or
- _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN or
- _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY,
- "illegal rounding mode")
+ _z3_assert(_dflt_rounding_mode in _ROUNDING_MODES, "illegal rounding mode")
_dflt_rounding_mode = rm
+
def get_default_fp_sort(ctx=None):
return FPSort(_dflt_fpsort_ebits, _dflt_fpsort_sbits, ctx)
+
def set_default_fp_sort(ebits, sbits, ctx=None):
global _dflt_fpsort_ebits
global _dflt_fpsort_sbits
_dflt_fpsort_ebits = ebits
_dflt_fpsort_sbits = sbits
+
def _dflt_rm(ctx=None):
return get_default_rounding_mode(ctx)
+
def _dflt_fps(ctx=None):
return get_default_fp_sort(ctx)
+
def _coerce_fp_expr_list(alist, ctx):
first_fp_sort = None
for a in alist:
@@ -8755,7 +9172,7 @@ def _coerce_fp_expr_list(alist, ctx):
if first_fp_sort is None:
first_fp_sort = a.sort()
elif first_fp_sort == a.sort():
- pass # OK, same as before
+ pass # OK, same as before
else:
# we saw at least 2 different float sorts; something will
# throw a sort mismatch later, for now assume None.
@@ -8765,33 +9182,34 @@ def _coerce_fp_expr_list(alist, ctx):
r = []
for i in range(len(alist)):
a = alist[i]
- if (isinstance(a, str) and a.contains('2**(') and a.endswith(')')) or _is_int(a) or isinstance(a, float) or isinstance(a, bool):
+ is_repr = isinstance(a, str) and a.contains("2**(") and a.endswith(")")
+ if is_repr or _is_int(a) or isinstance(a, (float, bool)):
r.append(FPVal(a, None, first_fp_sort, ctx))
else:
r.append(a)
return _coerce_expr_list(r, ctx)
-### FP Sorts
+# FP Sorts
class FPSortRef(SortRef):
"""Floating-point sort."""
def ebits(self):
- """Retrieves the number of bits reserved for the exponent in the FloatingPoint sort `self`.
- >>> b = FPSort(8, 24)
- >>> b.ebits()
- 8
- """
- return int(Z3_fpa_get_ebits(self.ctx_ref(), self.ast))
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint sort `self`.
+ >>> b = FPSort(8, 24)
+ >>> b.ebits()
+ 8
+ """
+ return int(Z3_fpa_get_ebits(self.ctx_ref(), self.ast))
def sbits(self):
- """Retrieves the number of bits reserved for the significand in the FloatingPoint sort `self`.
- >>> b = FPSort(8, 24)
- >>> b.sbits()
- 24
- """
- return int(Z3_fpa_get_sbits(self.ctx_ref(), self.ast))
+ """Retrieves the number of bits reserved for the significand in the FloatingPoint sort `self`.
+ >>> b = FPSort(8, 24)
+ >>> b.sbits()
+ 24
+ """
+ return int(Z3_fpa_get_sbits(self.ctx_ref(), self.ast))
def cast(self, val):
"""Try to cast `val` as a floating-point expression.
@@ -8814,41 +9232,49 @@ def Float16(ctx=None):
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_16(ctx.ref()), ctx)
+
def FloatHalf(ctx=None):
"""Floating-point 16-bit (half) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_half(ctx.ref()), ctx)
+
def Float32(ctx=None):
"""Floating-point 32-bit (single) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_32(ctx.ref()), ctx)
+
def FloatSingle(ctx=None):
"""Floating-point 32-bit (single) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_single(ctx.ref()), ctx)
+
def Float64(ctx=None):
"""Floating-point 64-bit (double) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_64(ctx.ref()), ctx)
+
def FloatDouble(ctx=None):
"""Floating-point 64-bit (double) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_double(ctx.ref()), ctx)
+
def Float128(ctx=None):
"""Floating-point 128-bit (quadruple) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_128(ctx.ref()), ctx)
+
def FloatQuadruple(ctx=None):
"""Floating-point 128-bit (quadruple) sort."""
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort_quadruple(ctx.ref()), ctx)
+
class FPRMSortRef(SortRef):
""""Floating-point rounding mode sort."""
@@ -8863,6 +9289,7 @@ def is_fp_sort(s):
"""
return isinstance(s, FPSortRef)
+
def is_fprm_sort(s):
"""Return True if `s` is a Z3 floating-point rounding mode sort.
@@ -8873,7 +9300,8 @@ def is_fprm_sort(s):
"""
return isinstance(s, FPRMSortRef)
-### FP Expressions
+# FP Expressions
+
class FPRef(ExprRef):
"""Floating-point expressions."""
@@ -8890,20 +9318,20 @@ class FPRef(ExprRef):
return FPSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
def ebits(self):
- """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`.
- >>> b = FPSort(8, 24)
- >>> b.ebits()
- 8
- """
- return self.sort().ebits();
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`.
+ >>> b = FPSort(8, 24)
+ >>> b.ebits()
+ 8
+ """
+ return self.sort().ebits()
def sbits(self):
- """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`.
- >>> b = FPSort(8, 24)
- >>> b.sbits()
- 24
- """
- return self.sort().sbits();
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`.
+ >>> b = FPSort(8, 24)
+ >>> b.sbits()
+ 24
+ """
+ return self.sort().sbits()
def as_string(self):
"""Return a Z3 floating point expression as a Python string."""
@@ -9052,6 +9480,7 @@ class FPRef(ExprRef):
"""Create the Z3 expression mod `other % self`."""
return fpRem(other, self)
+
class FPRMRef(ExprRef):
"""Floating-point rounding mode expressions"""
@@ -9064,42 +9493,52 @@ def RoundNearestTiesToEven(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx)
-def RNE (ctx=None):
+
+def RNE(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx)
+
def RoundNearestTiesToAway(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx)
-def RNA (ctx=None):
+
+def RNA(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx)
+
def RoundTowardPositive(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx)
+
def RTP(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx)
+
def RoundTowardNegative(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx)
+
def RTN(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx)
+
def RoundTowardZero(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx)
+
def RTZ(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx)
+
def is_fprm(a):
"""Return `True` if `a` is a Z3 floating-point rounding mode expression.
@@ -9112,11 +9551,13 @@ def is_fprm(a):
"""
return isinstance(a, FPRMRef)
+
def is_fprm_value(a):
"""Return `True` if `a` is a Z3 floating-point rounding mode numeral value."""
return is_fprm(a) and _is_numeral(a.ctx, a.ast)
-### FP Numerals
+# FP Numerals
+
class FPNumRef(FPRef):
"""The sign of the numeral.
@@ -9128,16 +9569,19 @@ class FPNumRef(FPRef):
>>> x.sign()
True
"""
+
def sign(self):
- l = (ctypes.c_int)()
- if Z3_fpa_get_numeral_sign(self.ctx.ref(), self.as_ast(), byref(l)) == False:
+ num = (ctypes.c_int)()
+ nsign = Z3_fpa_get_numeral_sign(self.ctx.ref(), self.as_ast(), byref(l))
+ if nsign is False:
raise Z3Exception("error retrieving the sign of a numeral.")
- return l.value != 0
+ return num.value != 0
"""The sign of a floating-point numeral as a bit-vector expression.
Remark: NaN's are invalid arguments.
"""
+
def sign_as_bv(self):
return BitVecNumRef(Z3_fpa_get_numeral_sign_bv(self.ctx.ref(), self.as_ast()), self.ctx)
@@ -9147,6 +9591,7 @@ class FPNumRef(FPRef):
>>> x.significand()
1.25
"""
+
def significand(self):
return Z3_fpa_get_numeral_significand_string(self.ctx.ref(), self.as_ast())
@@ -9156,6 +9601,7 @@ class FPNumRef(FPRef):
>>> x.significand_as_long()
1.25
"""
+
def significand_as_long(self):
ptr = (ctypes.c_ulonglong * 1)()
if not Z3_fpa_get_numeral_significand_uint64(self.ctx.ref(), self.as_ast(), ptr):
@@ -9166,6 +9612,7 @@ class FPNumRef(FPRef):
Remark: NaN are invalid arguments.
"""
+
def significand_as_bv(self):
return BitVecNumRef(Z3_fpa_get_numeral_significand_bv(self.ctx.ref(), self.as_ast()), self.ctx)
@@ -9175,6 +9622,7 @@ class FPNumRef(FPRef):
>>> x.exponent()
1
"""
+
def exponent(self, biased=True):
return Z3_fpa_get_numeral_exponent_string(self.ctx.ref(), self.as_ast(), biased)
@@ -9184,6 +9632,7 @@ class FPNumRef(FPRef):
>>> x.exponent_as_long()
1
"""
+
def exponent_as_long(self, biased=True):
ptr = (ctypes.c_longlong * 1)()
if not Z3_fpa_get_numeral_exponent_int64(self.ctx.ref(), self.as_ast(), ptr, biased):
@@ -9194,34 +9643,42 @@ class FPNumRef(FPRef):
Remark: NaNs are invalid arguments.
"""
+
def exponent_as_bv(self, biased=True):
return BitVecNumRef(Z3_fpa_get_numeral_exponent_bv(self.ctx.ref(), self.as_ast(), biased), self.ctx)
"""Indicates whether the numeral is a NaN."""
+
def isNaN(self):
return Z3_fpa_is_numeral_nan(self.ctx.ref(), self.as_ast())
"""Indicates whether the numeral is +oo or -oo."""
+
def isInf(self):
return Z3_fpa_is_numeral_inf(self.ctx.ref(), self.as_ast())
"""Indicates whether the numeral is +zero or -zero."""
+
def isZero(self):
return Z3_fpa_is_numeral_zero(self.ctx.ref(), self.as_ast())
"""Indicates whether the numeral is normal."""
+
def isNormal(self):
return Z3_fpa_is_numeral_normal(self.ctx.ref(), self.as_ast())
"""Indicates whether the numeral is subnormal."""
+
def isSubnormal(self):
return Z3_fpa_is_numeral_subnormal(self.ctx.ref(), self.as_ast())
"""Indicates whether the numeral is positive."""
+
def isPositive(self):
return Z3_fpa_is_numeral_positive(self.ctx.ref(), self.as_ast())
"""Indicates whether the numeral is negative."""
+
def isNegative(self):
return Z3_fpa_is_numeral_negative(self.ctx.ref(), self.as_ast())
@@ -9232,10 +9689,12 @@ class FPNumRef(FPRef):
>>> x.as_string()
1.25*(2**4)
"""
+
def as_string(self):
s = Z3_get_numeral_string(self.ctx.ref(), self.as_ast())
return ("FPVal(%s, %s)" % (s, self.sort()))
+
def is_fp(a):
"""Return `True` if `a` is a Z3 floating-point expression.
@@ -9249,6 +9708,7 @@ def is_fp(a):
"""
return isinstance(a, FPRef)
+
def is_fp_value(a):
"""Return `True` if `a` is a Z3 floating-point numeral value.
@@ -9263,6 +9723,7 @@ def is_fp_value(a):
"""
return is_fp(a) and _is_numeral(a.ctx, a.ast)
+
def FPSort(ebits, sbits, ctx=None):
"""Return a Z3 floating-point sort of the given sizes. If `ctx=None`, then the global context is used.
@@ -9277,6 +9738,7 @@ def FPSort(ebits, sbits, ctx=None):
ctx = _get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort(ctx.ref(), ebits, sbits), ctx)
+
def _to_float_str(val, exp=0):
if isinstance(val, float):
if math.isnan(val):
@@ -9295,8 +9757,8 @@ def _to_float_str(val, exp=0):
v = val.as_integer_ratio()
num = v[0]
den = v[1]
- rvs = str(num) + '/' + str(den)
- res = rvs + 'p' + _to_int_str(exp)
+ rvs = str(num) + "/" + str(den)
+ res = rvs + "p" + _to_int_str(exp)
elif isinstance(val, bool):
if val:
res = "1.0"
@@ -9305,12 +9767,12 @@ def _to_float_str(val, exp=0):
elif _is_int(val):
res = str(val)
elif isinstance(val, str):
- inx = val.find('*(2**')
+ inx = val.find("*(2**")
if inx == -1:
res = val
- elif val[-1] == ')':
+ elif val[-1] == ")":
res = val[0:inx]
- exp = str(int(val[inx+5:-1]) + int(exp))
+ exp = str(int(val[inx + 5:-1]) + int(exp))
else:
_z3_assert(False, "String does not have floating-point numeral form.")
elif z3_debug():
@@ -9318,7 +9780,7 @@ def _to_float_str(val, exp=0):
if exp == 0:
return res
else:
- return res + 'p' + exp
+ return res + "p" + exp
def fpNaN(s):
@@ -9337,6 +9799,7 @@ def fpNaN(s):
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_nan(s.ctx_ref(), s.ast), s.ctx)
+
def fpPlusInfinity(s):
"""Create a Z3 floating-point +oo term.
@@ -9353,35 +9816,42 @@ def fpPlusInfinity(s):
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, False), s.ctx)
+
def fpMinusInfinity(s):
"""Create a Z3 floating-point -oo term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, True), s.ctx)
+
def fpInfinity(s, negative):
"""Create a Z3 floating-point +oo or -oo term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
_z3_assert(isinstance(negative, bool), "expected Boolean flag")
return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, negative), s.ctx)
+
def fpPlusZero(s):
"""Create a Z3 floating-point +0.0 term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, False), s.ctx)
+
def fpMinusZero(s):
"""Create a Z3 floating-point -0.0 term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, True), s.ctx)
+
def fpZero(s, negative):
"""Create a Z3 floating-point +0.0 or -0.0 term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
_z3_assert(isinstance(negative, bool), "expected Boolean flag")
return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, negative), s.ctx)
+
def FPVal(sig, exp=None, fps=None, ctx=None):
- """Return a floating-point value of value `val` and sort `fps`. If `ctx=None`, then the global context is used.
+ """Return a floating-point value of value `val` and sort `fps`.
+ If `ctx=None`, then the global context is used.
>>> v = FPVal(20.0, FPSort(8, 24))
>>> v
@@ -9424,6 +9894,7 @@ def FPVal(sig, exp=None, fps=None, ctx=None):
else:
return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx)
+
def FP(name, fpsort, ctx=None):
"""Return a floating-point constant named `name`.
`fpsort` is the floating-point sort.
@@ -9447,6 +9918,7 @@ def FP(name, fpsort, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), fpsort.ast), ctx)
+
def FPs(names, fpsort, ctx=None):
"""Return an array of floating-point constants.
@@ -9465,6 +9937,7 @@ def FPs(names, fpsort, ctx=None):
names = names.split(" ")
return [FP(name, fpsort, ctx) for name in names]
+
def fpAbs(a, ctx=None):
"""Create a Z3 floating-point absolute value expression.
@@ -9487,6 +9960,7 @@ def fpAbs(a, ctx=None):
[a] = _coerce_fp_expr_list([a], ctx)
return FPRef(Z3_mk_fpa_abs(ctx.ref(), a.as_ast()), ctx)
+
def fpNeg(a, ctx=None):
"""Create a Z3 floating-point addition expression.
@@ -9502,6 +9976,7 @@ def fpNeg(a, ctx=None):
[a] = _coerce_fp_expr_list([a], ctx)
return FPRef(Z3_mk_fpa_neg(ctx.ref(), a.as_ast()), ctx)
+
def _mk_fp_unary(f, rm, a, ctx):
ctx = _get_ctx(ctx)
[a] = _coerce_fp_expr_list([a], ctx)
@@ -9510,6 +9985,7 @@ def _mk_fp_unary(f, rm, a, ctx):
_z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expression")
return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast()), ctx)
+
def _mk_fp_unary_pred(f, a, ctx):
ctx = _get_ctx(ctx)
[a] = _coerce_fp_expr_list([a], ctx)
@@ -9517,6 +9993,7 @@ def _mk_fp_unary_pred(f, a, ctx):
_z3_assert(is_fp(a), "First argument must be a Z3 floating-point expression")
return BoolRef(f(ctx.ref(), a.as_ast()), ctx)
+
def _mk_fp_bin(f, rm, a, b, ctx):
ctx = _get_ctx(ctx)
[a, b] = _coerce_fp_expr_list([a, b], ctx)
@@ -9525,6 +10002,7 @@ def _mk_fp_bin(f, rm, a, b, ctx):
_z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast(), b.as_ast()), ctx)
+
def _mk_fp_bin_norm(f, a, b, ctx):
ctx = _get_ctx(ctx)
[a, b] = _coerce_fp_expr_list([a, b], ctx)
@@ -9532,6 +10010,7 @@ def _mk_fp_bin_norm(f, a, b, ctx):
_z3_assert(is_fp(a) or is_fp(b), "First or second argument must be a Z3 floating-point expression")
return FPRef(f(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
def _mk_fp_bin_pred(f, a, b, ctx):
ctx = _get_ctx(ctx)
[a, b] = _coerce_fp_expr_list([a, b], ctx)
@@ -9539,14 +10018,17 @@ def _mk_fp_bin_pred(f, a, b, ctx):
_z3_assert(is_fp(a) or is_fp(b), "First or second argument must be a Z3 floating-point expression")
return BoolRef(f(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
def _mk_fp_tern(f, rm, a, b, c, ctx):
ctx = _get_ctx(ctx)
[a, b, c] = _coerce_fp_expr_list([a, b, c], ctx)
if z3_debug():
_z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a) or is_fp(b) or is_fp(c), "Second, third or fourth argument must be a Z3 floating-point expression")
+ _z3_assert(is_fp(a) or is_fp(b) or is_fp(
+ c), "Second, third or fourth argument must be a Z3 floating-point expression")
return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), ctx)
+
def fpAdd(rm, a, b, ctx=None):
"""Create a Z3 floating-point addition expression.
@@ -9563,6 +10045,7 @@ def fpAdd(rm, a, b, ctx=None):
"""
return _mk_fp_bin(Z3_mk_fpa_add, rm, a, b, ctx)
+
def fpSub(rm, a, b, ctx=None):
"""Create a Z3 floating-point subtraction expression.
@@ -9577,6 +10060,7 @@ def fpSub(rm, a, b, ctx=None):
"""
return _mk_fp_bin(Z3_mk_fpa_sub, rm, a, b, ctx)
+
def fpMul(rm, a, b, ctx=None):
"""Create a Z3 floating-point multiplication expression.
@@ -9591,6 +10075,7 @@ def fpMul(rm, a, b, ctx=None):
"""
return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx)
+
def fpDiv(rm, a, b, ctx=None):
"""Create a Z3 floating-point division expression.
@@ -9605,6 +10090,7 @@ def fpDiv(rm, a, b, ctx=None):
"""
return _mk_fp_bin(Z3_mk_fpa_div, rm, a, b, ctx)
+
def fpRem(a, b, ctx=None):
"""Create a Z3 floating-point remainder expression.
@@ -9618,6 +10104,7 @@ def fpRem(a, b, ctx=None):
"""
return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx)
+
def fpMin(a, b, ctx=None):
"""Create a Z3 floating-point minimum expression.
@@ -9632,6 +10119,7 @@ def fpMin(a, b, ctx=None):
"""
return _mk_fp_bin_norm(Z3_mk_fpa_min, a, b, ctx)
+
def fpMax(a, b, ctx=None):
"""Create a Z3 floating-point maximum expression.
@@ -9646,21 +10134,25 @@ def fpMax(a, b, ctx=None):
"""
return _mk_fp_bin_norm(Z3_mk_fpa_max, a, b, ctx)
+
def fpFMA(rm, a, b, c, ctx=None):
"""Create a Z3 floating-point fused multiply-add expression.
"""
return _mk_fp_tern(Z3_mk_fpa_fma, rm, a, b, c, ctx)
+
def fpSqrt(rm, a, ctx=None):
"""Create a Z3 floating-point square root expression.
"""
return _mk_fp_unary(Z3_mk_fpa_sqrt, rm, a, ctx)
+
def fpRoundToIntegral(rm, a, ctx=None):
"""Create a Z3 floating-point roundToIntegral expression.
"""
return _mk_fp_unary(Z3_mk_fpa_round_to_integral, rm, a, ctx)
+
def fpIsNaN(a, ctx=None):
"""Create a Z3 floating-point isNaN expression.
@@ -9672,6 +10164,7 @@ def fpIsNaN(a, ctx=None):
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_nan, a, ctx)
+
def fpIsInf(a, ctx=None):
"""Create a Z3 floating-point isInfinite expression.
@@ -9682,35 +10175,42 @@ def fpIsInf(a, ctx=None):
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_infinite, a, ctx)
+
def fpIsZero(a, ctx=None):
"""Create a Z3 floating-point isZero expression.
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_zero, a, ctx)
+
def fpIsNormal(a, ctx=None):
"""Create a Z3 floating-point isNormal expression.
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_normal, a, ctx)
+
def fpIsSubnormal(a, ctx=None):
"""Create a Z3 floating-point isSubnormal expression.
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_subnormal, a, ctx)
+
def fpIsNegative(a, ctx=None):
"""Create a Z3 floating-point isNegative expression.
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_negative, a, ctx)
+
def fpIsPositive(a, ctx=None):
"""Create a Z3 floating-point isPositive expression.
"""
return _mk_fp_unary_pred(Z3_mk_fpa_is_positive, a, ctx)
+
def _check_fp_args(a, b):
if z3_debug():
_z3_assert(is_fp(a) or is_fp(b), "First or second argument must be a Z3 floating-point expression")
+
def fpLT(a, b, ctx=None):
"""Create the Z3 floating-point expression `other < self`.
@@ -9722,6 +10222,7 @@ def fpLT(a, b, ctx=None):
"""
return _mk_fp_bin_pred(Z3_mk_fpa_lt, a, b, ctx)
+
def fpLEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
@@ -9733,6 +10234,7 @@ def fpLEQ(a, b, ctx=None):
"""
return _mk_fp_bin_pred(Z3_mk_fpa_leq, a, b, ctx)
+
def fpGT(a, b, ctx=None):
"""Create the Z3 floating-point expression `other > self`.
@@ -9744,6 +10246,7 @@ def fpGT(a, b, ctx=None):
"""
return _mk_fp_bin_pred(Z3_mk_fpa_gt, a, b, ctx)
+
def fpGEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `other >= self`.
@@ -9755,6 +10258,7 @@ def fpGEQ(a, b, ctx=None):
"""
return _mk_fp_bin_pred(Z3_mk_fpa_geq, a, b, ctx)
+
def fpEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `fpEQ(other, self)`.
@@ -9766,6 +10270,7 @@ def fpEQ(a, b, ctx=None):
"""
return _mk_fp_bin_pred(Z3_mk_fpa_eq, a, b, ctx)
+
def fpNEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `Not(fpEQ(other, self))`.
@@ -9777,6 +10282,7 @@ def fpNEQ(a, b, ctx=None):
"""
return Not(fpEQ(a, b, ctx))
+
def fpFP(sgn, exp, sig, ctx=None):
"""Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectors sgn, sig, and exp.
@@ -9805,6 +10311,7 @@ def fpFP(sgn, exp, sig, ctx=None):
_z3_assert(ctx == sgn.ctx == exp.ctx == sig.ctx, "context mismatch")
return FPRef(Z3_mk_fpa_fp(ctx.ref(), sgn.ast, exp.ast, sig.ast), ctx)
+
def fpToFP(a1, a2=None, a3=None, ctx=None):
"""Create a Z3 floating-point conversion expression from other term sorts
to floating-point.
@@ -9843,6 +10350,7 @@ def fpToFP(a1, a2=None, a3=None, ctx=None):
else:
raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.")
+
def fpBVToFP(v, sort, ctx=None):
"""Create a Z3 floating-point conversion expression that represents the
conversion from a bit-vector term to a floating-point term.
@@ -9859,6 +10367,7 @@ def fpBVToFP(v, sort, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_fpa_to_fp_bv(ctx.ref(), v.ast, sort.ast), ctx)
+
def fpFPToFP(rm, v, sort, ctx=None):
"""Create a Z3 floating-point conversion expression that represents the
conversion from a floating-point term to a floating-point term of different precision.
@@ -9878,6 +10387,7 @@ def fpFPToFP(rm, v, sort, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_fpa_to_fp_float(ctx.ref(), rm.ast, v.ast, sort.ast), ctx)
+
def fpRealToFP(rm, v, sort, ctx=None):
"""Create a Z3 floating-point conversion expression that represents the
conversion from a real term to a floating-point term.
@@ -9895,6 +10405,7 @@ def fpRealToFP(rm, v, sort, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_fpa_to_fp_real(ctx.ref(), rm.ast, v.ast, sort.ast), ctx)
+
def fpSignedToFP(rm, v, sort, ctx=None):
"""Create a Z3 floating-point conversion expression that represents the
conversion from a signed bit-vector term (encoding an integer) to a floating-point term.
@@ -9912,6 +10423,7 @@ def fpSignedToFP(rm, v, sort, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_fpa_to_fp_signed(ctx.ref(), rm.ast, v.ast, sort.ast), ctx)
+
def fpUnsignedToFP(rm, v, sort, ctx=None):
"""Create a Z3 floating-point conversion expression that represents the
conversion from an unsigned bit-vector term (encoding an integer) to a floating-point term.
@@ -9929,6 +10441,7 @@ def fpUnsignedToFP(rm, v, sort, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_fpa_to_fp_unsigned(ctx.ref(), rm.ast, v.ast, sort.ast), ctx)
+
def fpToFPUnsigned(rm, x, s, ctx=None):
"""Create a Z3 floating-point conversion expression, from unsigned bit-vector to floating-point expression."""
if z3_debug():
@@ -9938,6 +10451,7 @@ def fpToFPUnsigned(rm, x, s, ctx=None):
ctx = _get_ctx(ctx)
return FPRef(Z3_mk_fpa_to_fp_unsigned(ctx.ref(), rm.ast, x.ast, s.ast), ctx)
+
def fpToSBV(rm, x, s, ctx=None):
"""Create a Z3 floating-point conversion expression, from floating-point expression to signed bit-vector.
@@ -9959,6 +10473,7 @@ def fpToSBV(rm, x, s, ctx=None):
ctx = _get_ctx(ctx)
return BitVecRef(Z3_mk_fpa_to_sbv(ctx.ref(), rm.ast, x.ast, s.size()), ctx)
+
def fpToUBV(rm, x, s, ctx=None):
"""Create a Z3 floating-point conversion expression, from floating-point expression to unsigned bit-vector.
@@ -9980,6 +10495,7 @@ def fpToUBV(rm, x, s, ctx=None):
ctx = _get_ctx(ctx)
return BitVecRef(Z3_mk_fpa_to_ubv(ctx.ref(), rm.ast, x.ast, s.size()), ctx)
+
def fpToReal(x, ctx=None):
"""Create a Z3 floating-point conversion expression, from floating-point expression to real.
@@ -9999,6 +10515,7 @@ def fpToReal(x, ctx=None):
ctx = _get_ctx(ctx)
return ArithRef(Z3_mk_fpa_to_real(ctx.ref(), x.ast), ctx)
+
def fpToIEEEBV(x, ctx=None):
"""\brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format.
@@ -10025,7 +10542,6 @@ def fpToIEEEBV(x, ctx=None):
return BitVecRef(Z3_mk_fpa_to_ieee_bv(ctx.ref(), x.ast), ctx)
-
#########################################
#
# Strings, Sequences and Regular expressions
@@ -10068,6 +10584,7 @@ def SeqSort(s):
"""
return SeqSortRef(Z3_mk_seq_sort(s.ctx_ref(), s.ast), s.ctx)
+
class SeqRef(ExprRef):
"""Sequence expression."""
@@ -10096,13 +10613,12 @@ class SeqRef(ExprRef):
def is_string_value(self):
return Z3_is_string(self.ctx_ref(), self.as_ast())
-
def as_string(self):
"""Return a string representation of sequence expression."""
if self.is_string_value():
string_length = ctypes.c_uint()
chars = Z3_get_lstring(self.ctx_ref(), self.as_ast(), byref(string_length))
- return string_at(chars, size=string_length.value).decode('latin-1')
+ return string_at(chars, size=string_length.value).decode("latin-1")
return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
def __le__(self, other):
@@ -10128,6 +10644,7 @@ def _coerce_seq(s, ctx=None):
raise Z3Exception("Non-sequence passed as a sequence")
return s
+
def _get_ctx2(a, b, ctx=None):
if is_expr(a):
return a.ctx
@@ -10137,6 +10654,7 @@ def _get_ctx2(a, b, ctx=None):
ctx = main_ctx()
return ctx
+
def is_seq(a):
"""Return `True` if `a` is a Z3 sequence expression.
>>> print (is_seq(Unit(IntVal(0))))
@@ -10146,6 +10664,7 @@ def is_seq(a):
"""
return isinstance(a, SeqRef)
+
def is_string(a):
"""Return `True` if `a` is a Z3 string expression.
>>> print (is_string(StringVal("ab")))
@@ -10153,6 +10672,7 @@ def is_string(a):
"""
return isinstance(a, SeqRef) and a.is_string()
+
def is_string_value(a):
"""return 'True' if 'a' is a Z3 string constant expression.
>>> print (is_string_value(StringVal("a")))
@@ -10169,6 +10689,7 @@ def StringVal(s, ctx=None):
ctx = _get_ctx(ctx)
return SeqRef(Z3_mk_lstring(ctx.ref(), len(s), s), ctx)
+
def String(name, ctx=None):
"""Return a string constant named `name`. If `ctx=None`, then the global context is used.
@@ -10177,20 +10698,6 @@ def String(name, ctx=None):
ctx = _get_ctx(ctx)
return SeqRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), StringSort(ctx).ast), ctx)
-def Strings(names, ctx=None):
- """Return string constants"""
- ctx = _get_ctx(ctx)
- if isinstance(names, str):
- names = names.split(" ")
- return [String(name, ctx) for name in names]
-
-def SubString(s, offset, length):
- """Extract substring or subsequence starting at offset"""
- return Extract(s, offset, length)
-
-def SubSeq(s, offset, length):
- """Extract substring or subsequence starting at offset"""
- return Extract(s, offset, length)
def Strings(names, ctx=None):
"""Return a tuple of String constants. """
@@ -10199,6 +10706,17 @@ def Strings(names, ctx=None):
names = names.split(" ")
return [String(name, ctx) for name in names]
+
+def SubString(s, offset, length):
+ """Extract substring or subsequence starting at offset"""
+ return Extract(s, offset, length)
+
+
+def SubSeq(s, offset, length):
+ """Extract substring or subsequence starting at offset"""
+ return Extract(s, offset, length)
+
+
def Empty(s):
"""Create the empty sequence of the given sort
>>> e = Empty(StringSort())
@@ -10213,11 +10731,12 @@ def Empty(s):
Empty(ReSort(Seq(Int)))
"""
if isinstance(s, SeqSortRef):
- return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx)
+ return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx)
if isinstance(s, ReSortRef):
- return ReRef(Z3_mk_re_empty(s.ctx_ref(), s.ast), s.ctx)
+ return ReRef(Z3_mk_re_empty(s.ctx_ref(), s.ast), s.ctx)
raise Z3Exception("Non-sequence, non-regular expression sort passed to Empty")
+
def Full(s):
"""Create the regular expression that accepts the universal language
>>> e = Full(ReSort(SeqSort(IntSort())))
@@ -10228,7 +10747,7 @@ def Full(s):
Full(ReSort(String))
"""
if isinstance(s, ReSortRef):
- return ReRef(Z3_mk_re_full(s.ctx_ref(), s.ast), s.ctx)
+ return ReRef(Z3_mk_re_full(s.ctx_ref(), s.ast), s.ctx)
raise Z3Exception("Non-sequence, non-regular expression sort passed to Full")
@@ -10236,6 +10755,7 @@ def Unit(a):
"""Create a singleton sequence"""
return SeqRef(Z3_mk_seq_unit(a.ctx_ref(), a.as_ast()), a.ctx)
+
def PrefixOf(a, b):
"""Check if 'a' is a prefix of 'b'
>>> s1 = PrefixOf("ab", "abc")
@@ -10250,6 +10770,7 @@ def PrefixOf(a, b):
b = _coerce_seq(b, ctx)
return BoolRef(Z3_mk_seq_prefix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def SuffixOf(a, b):
"""Check if 'a' is a suffix of 'b'
>>> s1 = SuffixOf("ab", "abc")
@@ -10264,6 +10785,7 @@ def SuffixOf(a, b):
b = _coerce_seq(b, ctx)
return BoolRef(Z3_mk_seq_suffix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
def Contains(a, b):
"""Check if 'a' contains 'b'
>>> s1 = Contains("abc", "ab")
@@ -10294,19 +10816,19 @@ def Replace(s, src, dst):
ctx = src.ctx
src = _coerce_seq(src, ctx)
dst = _coerce_seq(dst, ctx)
- s = _coerce_seq(s, ctx)
+ s = _coerce_seq(s, ctx)
return SeqRef(Z3_mk_seq_replace(src.ctx_ref(), s.as_ast(), src.as_ast(), dst.as_ast()), s.ctx)
-def IndexOf(s, substr):
- return IndexOf(s, substr, IntVal(0))
-def IndexOf(s, substr, offset):
+def IndexOf(s, substr, offset=None):
"""Retrieve the index of substring within a string starting at a specified offset.
>>> simplify(IndexOf("abcabc", "bc", 0))
1
>>> simplify(IndexOf("abcabc", "bc", 2))
4
"""
+ if offset is None:
+ offset = IntVal(0)
ctx = None
if is_expr(offset):
ctx = offset.ctx
@@ -10317,6 +10839,7 @@ def IndexOf(s, substr, offset):
offset = IntVal(offset, ctx)
return ArithRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx)
+
def LastIndexOf(s, substr):
"""Retrieve the last index of substring within a string"""
ctx = None
@@ -10335,6 +10858,7 @@ def Length(s):
s = _coerce_seq(s)
return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx)
+
def StrToInt(s):
"""Convert string expression to integer
>>> a = StrToInt("1")
@@ -10368,9 +10892,7 @@ def Re(s, ctx=None):
return ReRef(Z3_mk_seq_to_re(s.ctx_ref(), s.as_ast()), s.ctx)
-
-
-## Regular expressions
+# Regular expressions
class ReSortRef(SortRef):
"""Regular expression sort."""
@@ -10378,6 +10900,7 @@ class ReSortRef(SortRef):
def basis(self):
return _to_sort_ref(Z3_get_re_sort_basis(self.ctx_ref(), self.ast), self.ctx)
+
def ReSort(s):
if is_ast(s):
return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.ast), s.ctx)
@@ -10393,6 +10916,7 @@ class ReRef(ExprRef):
def __add__(self, other):
return Union(self, other)
+
def is_re(s):
return isinstance(s, ReRef)
@@ -10410,6 +10934,7 @@ def InRe(s, re):
s = _coerce_seq(s, re.ctx)
return BoolRef(Z3_mk_seq_in_re(s.ctx_ref(), s.as_ast(), re.as_ast()), s.ctx)
+
def Union(*args):
"""Create union of regular expressions.
>>> re = Union(Re("a"), Re("b"), Re("c"))
@@ -10429,6 +10954,7 @@ def Union(*args):
v[i] = args[i].as_ast()
return ReRef(Z3_mk_re_union(ctx.ref(), sz, v), ctx)
+
def Intersect(*args):
"""Create intersection of regular expressions.
>>> re = Intersect(Re("a"), Re("b"), Re("c"))
@@ -10446,6 +10972,7 @@ def Intersect(*args):
v[i] = args[i].as_ast()
return ReRef(Z3_mk_re_intersect(ctx.ref(), sz, v), ctx)
+
def Plus(re):
"""Create the regular expression accepting one or more repetitions of argument.
>>> re = Plus(Re("a"))
@@ -10458,6 +10985,7 @@ def Plus(re):
"""
return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx)
+
def Option(re):
"""Create the regular expression that optionally accepts the argument.
>>> re = Option(Re("a"))
@@ -10470,10 +10998,12 @@ def Option(re):
"""
return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx)
+
def Complement(re):
"""Create the complement regular expression."""
return ReRef(Z3_mk_re_complement(re.ctx_ref(), re.as_ast()), re.ctx)
+
def Star(re):
"""Create the regular expression accepting zero or more repetitions of argument.
>>> re = Star(Re("a"))
@@ -10486,6 +11016,7 @@ def Star(re):
"""
return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx)
+
def Loop(re, lo, hi=0):
"""Create the regular expression accepting between a lower and upper bound repetitions
>>> re = Loop(Re("a"), 1, 3)
@@ -10498,7 +11029,8 @@ def Loop(re, lo, hi=0):
"""
return ReRef(Z3_mk_re_loop(re.ctx_ref(), re.as_ast(), lo, hi), re.ctx)
-def Range(lo, hi, ctx = None):
+
+def Range(lo, hi, ctx=None):
"""Create the range regular expression over two sequences of length 1
>>> range = Range("a","z")
>>> print(simplify(InRe("b", range)))
@@ -10512,17 +11044,22 @@ def Range(lo, hi, ctx = None):
# Special Relations
+
def PartialOrder(a, index):
- return FuncDeclRef(Z3_mk_partial_order(a.ctx_ref(), a.ast, index), a.ctx);
+ return FuncDeclRef(Z3_mk_partial_order(a.ctx_ref(), a.ast, index), a.ctx)
+
def LinearOrder(a, index):
- return FuncDeclRef(Z3_mk_linear_order(a.ctx_ref(), a.ast, index), a.ctx);
+ return FuncDeclRef(Z3_mk_linear_order(a.ctx_ref(), a.ast, index), a.ctx)
+
def TreeOrder(a, index):
- return FuncDeclRef(Z3_mk_tree_order(a.ctx_ref(), a.ast, index), a.ctx);
+ return FuncDeclRef(Z3_mk_tree_order(a.ctx_ref(), a.ast, index), a.ctx)
+
def PiecewiseLinearOrder(a, index):
- return FuncDeclRef(Z3_mk_piecewise_linear_order(a.ctx_ref(), a.ast, index), a.ctx);
+ return FuncDeclRef(Z3_mk_piecewise_linear_order(a.ctx_ref(), a.ast, index), a.ctx)
+
def TransitiveClosure(f):
"""Given a binary relation R, such that the two arguments have the same sort
@@ -10543,75 +11080,91 @@ class PropClosures:
self.lock = threading.thread.Lock()
def get(self, ctx):
- if self.lock: self.lock.acquire()
+ if self.lock:
+ self.lock.acquire()
r = self.bases[ctx]
- if self.lock: self.lock.release()
+ if self.lock:
+ self.lock.release()
return r
def set(self, ctx, r):
- if self.lock: self.lock.acquire()
+ if self.lock:
+ self.lock.acquire()
self.bases[ctx] = r
- if self.lock: self.lock.release()
+ if self.lock:
+ self.lock.release()
def insert(self, r):
- if self.lock: self.lock.acquire()
+ if self.lock:
+ self.lock.acquire()
id = len(self.bases) + 3
self.bases[id] = r
- if self.lock: self.lock.release()
+ if self.lock:
+ self.lock.release()
return id
+
_prop_closures = None
+
def ensure_prop_closures():
global _prop_closures
if _prop_closures is None:
_prop_closures = PropClosures()
+
def user_prop_push(ctx):
- _prop_closures.get(ctx).push();
+ _prop_closures.get(ctx).push()
+
def user_prop_pop(ctx, num_scopes):
_prop_closures.get(ctx).pop(num_scopes)
+
def user_prop_fresh(id, ctx):
- prop = _prop_closures.get(id)
_prop_closures.set_threaded()
new_prop = UsePropagateBase(None, ctx)
_prop_closures.set(new_prop.id, new_prop.fresh())
return ctypes.c_void_p(new_prop.id)
+
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()))
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
prop.eq(x, y)
prop.cb = None
+
def user_prop_diseq(ctx, cb, x, y):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.diseq(x, y)
prop.cb = None
-_user_prop_push = push_eh_type(user_prop_push)
-_user_prop_pop = pop_eh_type(user_prop_pop)
+
+_user_prop_push = push_eh_type(user_prop_push)
+_user_prop_pop = pop_eh_type(user_prop_pop)
_user_prop_fresh = fresh_eh_type(user_prop_fresh)
_user_prop_fixed = fixed_eh_type(user_prop_fixed)
_user_prop_final = final_eh_type(user_prop_final)
-_user_prop_eq = eq_eh_type(user_prop_eq)
+_user_prop_eq = eq_eh_type(user_prop_eq)
_user_prop_diseq = eq_eh_type(user_prop_diseq)
+
class UserPropagateBase:
#
@@ -10620,17 +11173,17 @@ class UserPropagateBase:
# to "fresh" inherit the context of that is supplied
# as argument to the callback.
# This context should not be deleted. It is owned by the solver.
- #
- def __init__(self, s, ctx = None):
+ #
+ def __init__(self, s, ctx=None):
assert s is None or ctx is None
ensure_prop_closures()
- self.solver = s
+ self.solver = s
self._ctx = None
self.cb = None
self.id = _prop_closures.insert(self)
self.fixed = None
self.final = None
- self.eq = None
+ self.eq = None
self.diseq = None
if ctx:
self._ctx = Context()
@@ -10655,16 +11208,16 @@ class UserPropagateBase:
return self._ctx
else:
return self.solver.ctx
-
+
def ctx_ref(self):
return self.ctx().ref()
-
+
def add_fixed(self, fixed):
assert not self.fixed
assert not self._ctx
Z3_solver_propagate_fixed(self.ctx_ref(), self.solver.solver, _user_prop_fixed)
self.fixed = fixed
-
+
def add_final(self, final):
assert not self.final
assert not self._ctx
@@ -10691,7 +11244,7 @@ class UserPropagateBase:
def fresh(self):
raise Z3Exception("fresh needs to be overwritten")
-
+
def add(self, e):
assert self.solver
assert not self._ctx
@@ -10699,8 +11252,8 @@ class UserPropagateBase:
#
# Propagation can only be invoked as during a fixed or final callback.
- #
- def propagate(self, e, ids, eqs = []):
+ #
+ def propagate(self, e, ids, eqs=[]):
num_fixed = len(ids)
_ids = (ctypes.c_uint * num_fixed)()
for i in range(num_fixed):
@@ -10711,7 +11264,8 @@ class UserPropagateBase:
for i in range(num_eqs):
_lhs[i] = eqs[i][0]
_rhs[i] = eqs[i][1]
- Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p(self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast)
+ 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=[])
diff --git a/src/api/python/z3/z3num.py b/src/api/python/z3/z3num.py
index b1af58dc3..09415d474 100644
--- a/src/api/python/z3/z3num.py
+++ b/src/api/python/z3/z3num.py
@@ -1,6 +1,6 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
+#
# Z3 Python interface for Z3 numerals
#
# Author: Leonardo de Moura (leonardo)
@@ -12,18 +12,20 @@ from fractions import Fraction
from .z3 import _get_ctx
+
def _to_numeral(num, ctx=None):
if isinstance(num, Numeral):
return num
else:
return Numeral(num, ctx)
+
class Numeral:
"""
A Z3 numeral can be used to perform computations over arbitrary
precision integers, rationals and real algebraic numbers.
It also automatically converts python numeric values.
-
+
>>> Numeral(2)
2
>>> Numeral("3/2") + 1
@@ -35,9 +37,9 @@ class Numeral:
>>> Numeral(Sqrt(2)) + Numeral(Sqrt(3))
3.1462643699?
- Z3 numerals can be used to perform computations with
+ Z3 numerals can be used to perform computations with
values in a Z3 model.
-
+
>>> s = Solver()
>>> x = Real('x')
>>> s.add(x*x == 2)
@@ -49,34 +51,34 @@ class Numeral:
1.4142135623?
>>> m[x] + 1
1.4142135623? + 1
-
+
The previous result is a Z3 expression.
>>> (m[x] + 1).sexpr()
'(+ (root-obj (+ (^ x 2) (- 2)) 2) 1.0)'
-
+
>>> Numeral(m[x]) + 1
2.4142135623?
>>> Numeral(m[x]).is_pos()
True
>>> Numeral(m[x])**2
2
-
+
We can also isolate the roots of polynomials.
>>> x0, x1, x2 = RealVarVector(3)
>>> r0 = isolate_roots(x0**5 - x0 - 1)
>>> r0
[1.1673039782?]
-
+
In the following example, we are isolating the roots
of a univariate polynomial (on x1) obtained after substituting
x0 -> r0[0]
-
+
>>> r1 = isolate_roots(x1**2 - x0 + 1, [ r0[0] ])
>>> r1
[-0.4090280898?, 0.4090280898?]
-
+
Similarly, in the next example we isolate the roots of
a univariate polynomial (on x2) obtained after substituting
x0 -> r0[0] and x1 -> r1[0]
@@ -85,10 +87,11 @@ class Numeral:
[2.8538479564?]
"""
+
def __init__(self, num, ctx=None):
if isinstance(num, Ast):
- self.ast = num
- self.ctx = _get_ctx(ctx)
+ self.ast = num
+ self.ctx = _get_ctx(ctx)
elif isinstance(num, RatNumRef) or isinstance(num, AlgebraicNumRef):
self.ast = num.ast
self.ctx = num.ctx
@@ -102,13 +105,13 @@ class Numeral:
self.ctx = v.ctx
Z3_inc_ref(self.ctx_ref(), self.as_ast())
assert Z3_algebraic_is_value(self.ctx_ref(), self.ast)
-
+
def __del__(self):
Z3_dec_ref(self.ctx_ref(), self.as_ast())
def is_integer(self):
""" Return True if the numeral is integer.
-
+
>>> Numeral(2).is_integer()
True
>>> (Numeral(Sqrt(2)) * Numeral(Sqrt(2))).is_integer()
@@ -129,13 +132,13 @@ class Numeral:
True
>>> Numeral(Sqrt(2)).is_rational()
False
-
+
"""
return Z3_get_ast_kind(self.ctx_ref(), self.as_ast()) == Z3_NUMERAL_AST
def denominator(self):
""" Return the denominator if `self` is rational.
-
+
>>> Numeral("2/3").denominator()
3
"""
@@ -144,14 +147,13 @@ class Numeral:
def numerator(self):
""" Return the numerator if `self` is rational.
-
+
>>> Numeral("2/3").numerator()
2
"""
assert(self.is_rational())
return Numeral(Z3_get_numerator(self.ctx_ref(), self.as_ast()), self.ctx)
-
def is_irrational(self):
""" Return True if the numeral is irrational.
@@ -169,7 +171,7 @@ class Numeral:
"""
assert(self.is_integer())
- if sys.version_info[0] >= 3:
+ if sys.version_info.major >= 3:
return int(Z3_get_numeral_string(self.ctx_ref(), self.as_ast()))
else:
return long(Z3_get_numeral_string(self.ctx_ref(), self.as_ast()))
@@ -183,9 +185,9 @@ class Numeral:
return Fraction(self.numerator().as_long(), self.denominator().as_long())
def approx(self, precision=10):
- """Return a numeral that approximates the numeral `self`.
- The result `r` is such that |r - self| <= 1/10^precision
-
+ """Return a numeral that approximates the numeral `self`.
+ The result `r` is such that |r - self| <= 1/10^precision
+
If `self` is rational, then the result is `self`.
>>> x = Numeral(2).root(2)
@@ -199,9 +201,9 @@ class Numeral:
return self.upper(precision)
def upper(self, precision=10):
- """Return a upper bound that approximates the numeral `self`.
- The result `r` is such that r - self <= 1/10^precision
-
+ """Return a upper bound that approximates the numeral `self`.
+ The result `r` is such that r - self <= 1/10^precision
+
If `self` is rational, then the result is `self`.
>>> x = Numeral(2).root(2)
@@ -218,9 +220,9 @@ class Numeral:
return Numeral(Z3_get_algebraic_number_upper(self.ctx_ref(), self.as_ast(), precision), self.ctx)
def lower(self, precision=10):
- """Return a lower bound that approximates the numeral `self`.
- The result `r` is such that self - r <= 1/10^precision
-
+ """Return a lower bound that approximates the numeral `self`.
+ The result `r` is such that self - r <= 1/10^precision
+
If `self` is rational, then the result is `self`.
>>> x = Numeral(2).root(2)
@@ -236,7 +238,7 @@ class Numeral:
def sign(self):
""" Return the sign of the numeral.
-
+
>>> Numeral(2).sign()
1
>>> Numeral(-3).sign()
@@ -245,10 +247,10 @@ class Numeral:
0
"""
return Z3_algebraic_sign(self.ctx_ref(), self.ast)
-
+
def is_pos(self):
""" Return True if the numeral is positive.
-
+
>>> Numeral(2).is_pos()
True
>>> Numeral(-3).is_pos()
@@ -260,7 +262,7 @@ class Numeral:
def is_neg(self):
""" Return True if the numeral is negative.
-
+
>>> Numeral(2).is_neg()
False
>>> Numeral(-3).is_neg()
@@ -272,7 +274,7 @@ class Numeral:
def is_zero(self):
""" Return True if the numeral is zero.
-
+
>>> Numeral(2).is_zero()
False
>>> Numeral(-3).is_zero()
@@ -353,7 +355,7 @@ class Numeral:
def __rdiv__(self, other):
""" Return the numeral `other / self`.
- >>> 3 / Numeral(2)
+ >>> 3 / Numeral(2)
3/2
>>> 3 / Numeral(2).root(2)
2.1213203435?
@@ -388,7 +390,7 @@ class Numeral:
3
"""
return Numeral(Z3_algebraic_power(self.ctx_ref(), self.ast, k), self.ctx)
-
+
def __pow__(self, k):
""" Return the numeral `self^k`.
@@ -415,7 +417,7 @@ class Numeral:
def __rlt__(self, other):
""" Return True if `other < self`.
- >>> 2 < Numeral(Sqrt(2))
+ >>> 2 < Numeral(Sqrt(2))
False
"""
return self > other
@@ -440,7 +442,6 @@ class Numeral:
"""
return self < other
-
def __le__(self, other):
""" Return True if `self <= other`.
@@ -456,7 +457,7 @@ class Numeral:
def __rle__(self, other):
""" Return True if `other <= self`.
- >>> 2 <= Numeral(Sqrt(2))
+ >>> 2 <= Numeral(Sqrt(2))
False
"""
return self >= other
@@ -523,13 +524,14 @@ class Numeral:
def ctx_ref(self):
return self.ctx.ref()
+
def eval_sign_at(p, vs):
- """
+ """
Evaluate the sign of the polynomial `p` at `vs`. `p` is a Z3
Expression containing arithmetic operators: +, -, *, ^k where k is
an integer; and free variables x that is_var(x) is True. Moreover,
all variables must be real.
-
+
The result is 1 if the polynomial is positive at the given point,
-1 if negative, and 0 if zero.
@@ -547,15 +549,16 @@ def eval_sign_at(p, vs):
_vs[i] = vs[i].ast
return Z3_algebraic_eval(p.ctx_ref(), p.as_ast(), num, _vs)
+
def isolate_roots(p, vs=[]):
"""
- Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the
+ Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the
roots of the univariate polynomial p(vs[0], ..., vs[len(vs)-1], x_n).
-
+
Remarks:
* p is a Z3 expression that contains only arithmetic terms and free variables.
* forall i in [0, n) vs is a numeral.
-
+
The result is a list of numerals
>>> x0 = RealVar(0)
@@ -573,5 +576,4 @@ def isolate_roots(p, vs=[]):
for i in range(num):
_vs[i] = vs[i].ast
_roots = AstVector(Z3_algebraic_roots(p.ctx_ref(), p.as_ast(), num, _vs), p.ctx)
- return [ Numeral(r) for r in _roots ]
-
+ return [Numeral(r) for r in _roots]
diff --git a/src/api/python/z3/z3poly.py b/src/api/python/z3/z3poly.py
index 169944291..9c6e217f8 100644
--- a/src/api/python/z3/z3poly.py
+++ b/src/api/python/z3/z3poly.py
@@ -1,6 +1,6 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
+#
# Z3 Python interface for Z3 polynomials
#
# Author: Leonardo de Moura (leonardo)
@@ -8,16 +8,17 @@
from .z3 import *
+
def subresultants(p, q, x):
"""
Return the non-constant subresultants of 'p' and 'q' with respect to the "variable" 'x'.
'p', 'q' and 'x' are Z3 expressions where 'p' and 'q' are arithmetic terms.
Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable.
- Example: f(a) is a considered to be a variable b in the polynomial
+ Example: f(a) is a considered to be a variable b in the polynomial
+
+ f(a)*f(a) + 2*f(a) + 1
- f(a)*f(a) + 2*f(a) + 1
-
>>> x, y = Reals('x y')
>>> subresultants(2*x + y, 3*x - 2*y + 2, x)
[-7*y + 4]
@@ -29,6 +30,7 @@ def subresultants(p, q, x):
"""
return AstVector(Z3_polynomial_subresultants(p.ctx_ref(), p.as_ast(), q.as_ast(), x.as_ast()), p.ctx)
+
if __name__ == "__main__":
import doctest
if doctest.testmod().failed:
diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py
index 34e4bd69e..f9df0a99d 100644
--- a/src/api/python/z3/z3printer.py
+++ b/src/api/python/z3/z3printer.py
@@ -1,15 +1,16 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
+#
# Z3 Python interface
#
# Author: Leonardo de Moura (leonardo)
############################################
-import sys, io
+import sys
+import io
# We want to import submodule z3 here, but there's no way
# to do that that works correctly on both Python 2 and 3.
-if sys.version < '3':
+if sys.version_info.major < 3:
# In Python 2: an implicit-relative import of submodule z3.
# In Python 3: an undesirable import of global package z3.
import z3
@@ -22,6 +23,7 @@ from .z3consts import *
from .z3core import *
from ctypes import *
+
def _z3_assert(cond, msg):
if not cond:
raise Z3Exception(msg)
@@ -32,165 +34,277 @@ def _z3_assert(cond, msg):
#
##############################
+
# Z3 operator names to Z3Py
_z3_op_to_str = {
- Z3_OP_TRUE : 'True', Z3_OP_FALSE : 'False', Z3_OP_EQ : '==', Z3_OP_DISTINCT : 'Distinct',
- Z3_OP_ITE : 'If', Z3_OP_AND : 'And', Z3_OP_OR : 'Or', Z3_OP_IFF : '==', Z3_OP_XOR : 'Xor',
- Z3_OP_NOT : 'Not', Z3_OP_IMPLIES : 'Implies', Z3_OP_IDIV : '/', Z3_OP_MOD : '%',
- Z3_OP_TO_REAL : 'ToReal', Z3_OP_TO_INT : 'ToInt', Z3_OP_POWER : '**', Z3_OP_IS_INT : 'IsInt',
- Z3_OP_BADD : '+', Z3_OP_BSUB : '-', Z3_OP_BMUL : '*', Z3_OP_BOR : '|', Z3_OP_BAND : '&',
- Z3_OP_BNOT : '~', Z3_OP_BXOR : '^', Z3_OP_BNEG : '-', Z3_OP_BUDIV : 'UDiv', Z3_OP_BSDIV : '/', Z3_OP_BSMOD : '%',
- Z3_OP_BSREM : 'SRem', Z3_OP_BUREM : 'URem', Z3_OP_EXT_ROTATE_LEFT : 'RotateLeft', Z3_OP_EXT_ROTATE_RIGHT : 'RotateRight',
- Z3_OP_SLEQ : '<=', Z3_OP_SLT : '<', Z3_OP_SGEQ : '>=', Z3_OP_SGT : '>',
- Z3_OP_ULEQ : 'ULE', Z3_OP_ULT : 'ULT', Z3_OP_UGEQ : 'UGE', Z3_OP_UGT : 'UGT',
- Z3_OP_SIGN_EXT : 'SignExt', Z3_OP_ZERO_EXT : 'ZeroExt', Z3_OP_REPEAT : 'RepeatBitVec',
- Z3_OP_BASHR : '>>', Z3_OP_BSHL : '<<', Z3_OP_BLSHR : 'LShR',
- Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int',
- Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store',
- Z3_OP_CONST_ARRAY : 'K', Z3_OP_ARRAY_EXT : 'Ext',
- Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe', Z3_OP_PB_EQ : 'PbEq',
- Z3_OP_SEQ_CONCAT : 'Concat', Z3_OP_SEQ_PREFIX : 'PrefixOf', Z3_OP_SEQ_SUFFIX : 'SuffixOf',
- Z3_OP_SEQ_UNIT : 'Unit', Z3_OP_SEQ_CONTAINS : 'Contains' , Z3_OP_SEQ_REPLACE : 'Replace',
- Z3_OP_SEQ_AT : 'At', Z3_OP_SEQ_NTH : 'Nth', Z3_OP_SEQ_INDEX : 'IndexOf',
- Z3_OP_SEQ_LAST_INDEX : 'LastIndexOf', Z3_OP_SEQ_LENGTH : 'Length', Z3_OP_STR_TO_INT : 'StrToInt', Z3_OP_INT_TO_STR : 'IntToStr',
- Z3_OP_SEQ_IN_RE : 'InRe', Z3_OP_SEQ_TO_RE : 'Re',
- Z3_OP_RE_PLUS : 'Plus', Z3_OP_RE_STAR : 'Star', Z3_OP_RE_OPTION : 'Option', Z3_OP_RE_UNION : 'Union', Z3_OP_RE_RANGE : 'Range',
- Z3_OP_RE_INTERSECT : 'Intersect', Z3_OP_RE_COMPLEMENT : 'Complement',
- Z3_OP_FPA_IS_NAN : 'fpIsNaN', Z3_OP_FPA_IS_INF : 'fpIsInf', Z3_OP_FPA_IS_ZERO : 'fpIsZero',
- Z3_OP_FPA_IS_NORMAL : 'fpIsNormal', Z3_OP_FPA_IS_SUBNORMAL : 'fpIsSubnormal',
- Z3_OP_FPA_IS_NEGATIVE : 'fpIsNegative', Z3_OP_FPA_IS_POSITIVE : 'fpIsPositive',
- }
+ Z3_OP_TRUE: "True",
+ Z3_OP_FALSE: "False",
+ Z3_OP_EQ: "==",
+ Z3_OP_DISTINCT: "Distinct",
+ Z3_OP_ITE: "If",
+ Z3_OP_AND: "And",
+ Z3_OP_OR: "Or",
+ Z3_OP_IFF: "==",
+ Z3_OP_XOR: "Xor",
+ Z3_OP_NOT: "Not",
+ Z3_OP_IMPLIES: "Implies",
+
+ Z3_OP_IDIV: "/",
+ Z3_OP_MOD: "%",
+ Z3_OP_TO_REAL: "ToReal",
+ Z3_OP_TO_INT: "ToInt",
+ Z3_OP_POWER: "**",
+ Z3_OP_IS_INT: "IsInt",
+ Z3_OP_BADD: "+",
+ Z3_OP_BSUB: "-",
+ Z3_OP_BMUL: "*",
+ Z3_OP_BOR: "|",
+ Z3_OP_BAND: "&",
+ Z3_OP_BNOT: "~",
+ Z3_OP_BXOR: "^",
+ Z3_OP_BNEG: "-",
+ Z3_OP_BUDIV: "UDiv",
+ Z3_OP_BSDIV: "/",
+ Z3_OP_BSMOD: "%",
+ Z3_OP_BSREM: "SRem",
+ Z3_OP_BUREM: "URem",
+
+ Z3_OP_EXT_ROTATE_LEFT: "RotateLeft",
+ Z3_OP_EXT_ROTATE_RIGHT: "RotateRight",
+
+ Z3_OP_SLEQ: "<=",
+ Z3_OP_SLT: "<",
+ Z3_OP_SGEQ: ">=",
+ Z3_OP_SGT: ">",
+
+ Z3_OP_ULEQ: "ULE",
+ Z3_OP_ULT: "ULT",
+ Z3_OP_UGEQ: "UGE",
+ Z3_OP_UGT: "UGT",
+ Z3_OP_SIGN_EXT: "SignExt",
+ Z3_OP_ZERO_EXT: "ZeroExt",
+
+ Z3_OP_REPEAT: "RepeatBitVec",
+ Z3_OP_BASHR: ">>",
+ Z3_OP_BSHL: "<<",
+ Z3_OP_BLSHR: "LShR",
+
+ Z3_OP_CONCAT: "Concat",
+ Z3_OP_EXTRACT: "Extract",
+ Z3_OP_BV2INT: "BV2Int",
+ Z3_OP_ARRAY_MAP: "Map",
+ Z3_OP_SELECT: "Select",
+ Z3_OP_STORE: "Store",
+ Z3_OP_CONST_ARRAY: "K",
+ Z3_OP_ARRAY_EXT: "Ext",
+
+ Z3_OP_PB_AT_MOST: "AtMost",
+ Z3_OP_PB_LE: "PbLe",
+ Z3_OP_PB_GE: "PbGe",
+ Z3_OP_PB_EQ: "PbEq",
+
+ Z3_OP_SEQ_CONCAT: "Concat",
+ Z3_OP_SEQ_PREFIX: "PrefixOf",
+ Z3_OP_SEQ_SUFFIX: "SuffixOf",
+ Z3_OP_SEQ_UNIT: "Unit",
+ Z3_OP_SEQ_CONTAINS: "Contains",
+ Z3_OP_SEQ_REPLACE: "Replace",
+ Z3_OP_SEQ_AT: "At",
+ Z3_OP_SEQ_NTH: "Nth",
+ Z3_OP_SEQ_INDEX: "IndexOf",
+ Z3_OP_SEQ_LAST_INDEX: "LastIndexOf",
+ Z3_OP_SEQ_LENGTH: "Length",
+ Z3_OP_STR_TO_INT: "StrToInt",
+ Z3_OP_INT_TO_STR: "IntToStr",
+
+ Z3_OP_SEQ_IN_RE: "InRe",
+ Z3_OP_SEQ_TO_RE: "Re",
+ Z3_OP_RE_PLUS: "Plus",
+ Z3_OP_RE_STAR: "Star",
+ Z3_OP_RE_OPTION: "Option",
+ Z3_OP_RE_UNION: "Union",
+ Z3_OP_RE_RANGE: "Range",
+ Z3_OP_RE_INTERSECT: "Intersect",
+ Z3_OP_RE_COMPLEMENT: "Complement",
+
+ Z3_OP_FPA_IS_NAN: "fpIsNaN",
+ Z3_OP_FPA_IS_INF: "fpIsInf",
+ Z3_OP_FPA_IS_ZERO: "fpIsZero",
+ Z3_OP_FPA_IS_NORMAL: "fpIsNormal",
+ Z3_OP_FPA_IS_SUBNORMAL: "fpIsSubnormal",
+ Z3_OP_FPA_IS_NEGATIVE: "fpIsNegative",
+ Z3_OP_FPA_IS_POSITIVE: "fpIsPositive",
+}
# List of infix operators
-_z3_infix = [
+_z3_infix = [
Z3_OP_EQ, Z3_OP_IFF, Z3_OP_ADD, Z3_OP_SUB, Z3_OP_MUL, Z3_OP_DIV, Z3_OP_IDIV, Z3_OP_MOD, Z3_OP_POWER,
- Z3_OP_LE, Z3_OP_LT, Z3_OP_GE, Z3_OP_GT, Z3_OP_BADD, Z3_OP_BSUB, Z3_OP_BMUL, Z3_OP_BSDIV, Z3_OP_BSMOD, Z3_OP_BOR, Z3_OP_BAND,
- Z3_OP_BXOR, Z3_OP_BSDIV, Z3_OP_SLEQ, Z3_OP_SLT, Z3_OP_SGEQ, Z3_OP_SGT, Z3_OP_BASHR, Z3_OP_BSHL
- ]
+ Z3_OP_LE, Z3_OP_LT, Z3_OP_GE, Z3_OP_GT, Z3_OP_BADD, Z3_OP_BSUB, Z3_OP_BMUL,
+ Z3_OP_BSDIV, Z3_OP_BSMOD, Z3_OP_BOR, Z3_OP_BAND,
+ Z3_OP_BXOR, Z3_OP_BSDIV, Z3_OP_SLEQ, Z3_OP_SLT, Z3_OP_SGEQ, Z3_OP_SGT, Z3_OP_BASHR, Z3_OP_BSHL,
+]
-_z3_unary = [ Z3_OP_UMINUS, Z3_OP_BNOT, Z3_OP_BNEG ]
+_z3_unary = [Z3_OP_UMINUS, Z3_OP_BNOT, Z3_OP_BNEG]
# Precedence
_z3_precedence = {
- Z3_OP_POWER : 0,
- Z3_OP_UMINUS : 1, Z3_OP_BNEG : 1, Z3_OP_BNOT : 1,
- Z3_OP_MUL : 2, Z3_OP_DIV : 2, Z3_OP_IDIV : 2, Z3_OP_MOD : 2, Z3_OP_BMUL : 2, Z3_OP_BSDIV : 2, Z3_OP_BSMOD : 2,
- Z3_OP_ADD : 3, Z3_OP_SUB : 3, Z3_OP_BADD : 3, Z3_OP_BSUB : 3,
- Z3_OP_BASHR : 4, Z3_OP_BSHL : 4,
- Z3_OP_BAND : 5,
- Z3_OP_BXOR : 6,
- Z3_OP_BOR : 7,
- Z3_OP_LE : 8, Z3_OP_LT : 8, Z3_OP_GE : 8, Z3_OP_GT : 8, Z3_OP_EQ : 8, Z3_OP_SLEQ : 8, Z3_OP_SLT : 8, Z3_OP_SGEQ : 8, Z3_OP_SGT : 8,
- Z3_OP_IFF : 8,
-
- Z3_OP_FPA_NEG : 1,
- Z3_OP_FPA_MUL : 2, Z3_OP_FPA_DIV : 2, Z3_OP_FPA_REM : 2, Z3_OP_FPA_FMA : 2,
- Z3_OP_FPA_ADD: 3, Z3_OP_FPA_SUB : 3,
- Z3_OP_FPA_LE : 8, Z3_OP_FPA_LT : 8, Z3_OP_FPA_GE : 8, Z3_OP_FPA_GT : 8, Z3_OP_FPA_EQ : 8
- }
+ Z3_OP_POWER: 0,
+ Z3_OP_UMINUS: 1, Z3_OP_BNEG: 1, Z3_OP_BNOT: 1,
+ Z3_OP_MUL: 2, Z3_OP_DIV: 2, Z3_OP_IDIV: 2, Z3_OP_MOD: 2, Z3_OP_BMUL: 2, Z3_OP_BSDIV: 2, Z3_OP_BSMOD: 2,
+ Z3_OP_ADD: 3, Z3_OP_SUB: 3, Z3_OP_BADD: 3, Z3_OP_BSUB: 3,
+ Z3_OP_BASHR: 4, Z3_OP_BSHL: 4,
+ Z3_OP_BAND: 5,
+ Z3_OP_BXOR: 6,
+ Z3_OP_BOR: 7,
+ Z3_OP_LE: 8, Z3_OP_LT: 8, Z3_OP_GE: 8, Z3_OP_GT: 8, Z3_OP_EQ: 8, Z3_OP_SLEQ: 8,
+ Z3_OP_SLT: 8, Z3_OP_SGEQ: 8, Z3_OP_SGT: 8, Z3_OP_IFF: 8,
-# FPA operators
-_z3_op_to_fpa_normal_str = {
- Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RoundNearestTiesToEven()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RoundNearestTiesToAway()',
- Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RoundTowardPositive()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RoundTowardNegative()',
- Z3_OP_FPA_RM_TOWARD_ZERO : 'RoundTowardZero()',
- Z3_OP_FPA_PLUS_INF : 'fpPlusInfinity', Z3_OP_FPA_MINUS_INF : 'fpMinusInfinity',
- Z3_OP_FPA_NAN : 'fpNaN', Z3_OP_FPA_PLUS_ZERO : 'fpPZero', Z3_OP_FPA_MINUS_ZERO : 'fpNZero',
- Z3_OP_FPA_ADD : 'fpAdd', Z3_OP_FPA_SUB : 'fpSub', Z3_OP_FPA_NEG : 'fpNeg', Z3_OP_FPA_MUL : 'fpMul',
- Z3_OP_FPA_DIV : 'fpDiv', Z3_OP_FPA_REM : 'fpRem', Z3_OP_FPA_ABS : 'fpAbs',
- Z3_OP_FPA_MIN : 'fpMin', Z3_OP_FPA_MAX : 'fpMax',
- Z3_OP_FPA_FMA : 'fpFMA', Z3_OP_FPA_SQRT : 'fpSqrt', Z3_OP_FPA_ROUND_TO_INTEGRAL : 'fpRoundToIntegral',
-
- Z3_OP_FPA_EQ : 'fpEQ', Z3_OP_FPA_LT : 'fpLT', Z3_OP_FPA_GT : 'fpGT', Z3_OP_FPA_LE : 'fpLEQ',
- Z3_OP_FPA_GE : 'fpGEQ',
-
- Z3_OP_FPA_FP : 'fpFP', Z3_OP_FPA_TO_FP : 'fpToFP', Z3_OP_FPA_TO_FP_UNSIGNED: 'fpToFPUnsigned',
- Z3_OP_FPA_TO_UBV : 'fpToUBV', Z3_OP_FPA_TO_SBV : 'fpToSBV', Z3_OP_FPA_TO_REAL: 'fpToReal',
- Z3_OP_FPA_TO_IEEE_BV : 'fpToIEEEBV'
- }
-
-_z3_op_to_fpa_pretty_str = {
- Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RNE()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RNA()',
- Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RTP()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RTN()',
- Z3_OP_FPA_RM_TOWARD_ZERO : 'RTZ()',
- Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo',
- Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : '+0.0', Z3_OP_FPA_MINUS_ZERO : '-0.0',
-
- Z3_OP_FPA_ADD : '+', Z3_OP_FPA_SUB : '-', Z3_OP_FPA_MUL : '*', Z3_OP_FPA_DIV : '/',
- Z3_OP_FPA_REM : '%', Z3_OP_FPA_NEG : '-',
-
- Z3_OP_FPA_EQ : 'fpEQ', Z3_OP_FPA_LT : '<', Z3_OP_FPA_GT : '>', Z3_OP_FPA_LE : '<=', Z3_OP_FPA_GE : '>='
+ Z3_OP_FPA_NEG: 1,
+ Z3_OP_FPA_MUL: 2, Z3_OP_FPA_DIV: 2, Z3_OP_FPA_REM: 2, Z3_OP_FPA_FMA: 2,
+ Z3_OP_FPA_ADD: 3, Z3_OP_FPA_SUB: 3,
+ Z3_OP_FPA_LE: 8, Z3_OP_FPA_LT: 8, Z3_OP_FPA_GE: 8, Z3_OP_FPA_GT: 8, Z3_OP_FPA_EQ: 8,
}
-
+
+# FPA operators
+_z3_op_to_fpa_normal_str = {
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: "RoundNearestTiesToEven()",
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: "RoundNearestTiesToAway()",
+ Z3_OP_FPA_RM_TOWARD_POSITIVE: "RoundTowardPositive()",
+ Z3_OP_FPA_RM_TOWARD_NEGATIVE: "RoundTowardNegative()",
+ Z3_OP_FPA_RM_TOWARD_ZERO: "RoundTowardZero()",
+ Z3_OP_FPA_PLUS_INF: "fpPlusInfinity",
+ Z3_OP_FPA_MINUS_INF: "fpMinusInfinity",
+ Z3_OP_FPA_NAN: "fpNaN",
+ Z3_OP_FPA_PLUS_ZERO: "fpPZero",
+ Z3_OP_FPA_MINUS_ZERO: "fpNZero",
+ Z3_OP_FPA_ADD: "fpAdd",
+ Z3_OP_FPA_SUB: "fpSub",
+ Z3_OP_FPA_NEG: "fpNeg",
+ Z3_OP_FPA_MUL: "fpMul",
+ Z3_OP_FPA_DIV: "fpDiv",
+ Z3_OP_FPA_REM: "fpRem",
+ Z3_OP_FPA_ABS: "fpAbs",
+ Z3_OP_FPA_MIN: "fpMin",
+ Z3_OP_FPA_MAX: "fpMax",
+ Z3_OP_FPA_FMA: "fpFMA",
+ Z3_OP_FPA_SQRT: "fpSqrt",
+ Z3_OP_FPA_ROUND_TO_INTEGRAL: "fpRoundToIntegral",
+
+ Z3_OP_FPA_EQ: "fpEQ",
+ Z3_OP_FPA_LT: "fpLT",
+ Z3_OP_FPA_GT: "fpGT",
+ Z3_OP_FPA_LE: "fpLEQ",
+ Z3_OP_FPA_GE: "fpGEQ",
+
+ Z3_OP_FPA_FP: "fpFP",
+ Z3_OP_FPA_TO_FP: "fpToFP",
+ Z3_OP_FPA_TO_FP_UNSIGNED: "fpToFPUnsigned",
+ Z3_OP_FPA_TO_UBV: "fpToUBV",
+ Z3_OP_FPA_TO_SBV: "fpToSBV",
+ Z3_OP_FPA_TO_REAL: "fpToReal",
+ Z3_OP_FPA_TO_IEEE_BV: "fpToIEEEBV",
+}
+
+_z3_op_to_fpa_pretty_str = {
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: "RNE()", Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: "RNA()",
+ Z3_OP_FPA_RM_TOWARD_POSITIVE: "RTP()", Z3_OP_FPA_RM_TOWARD_NEGATIVE: "RTN()",
+ Z3_OP_FPA_RM_TOWARD_ZERO: "RTZ()",
+ Z3_OP_FPA_PLUS_INF: "+oo", Z3_OP_FPA_MINUS_INF: "-oo",
+ Z3_OP_FPA_NAN: "NaN", Z3_OP_FPA_PLUS_ZERO: "+0.0", Z3_OP_FPA_MINUS_ZERO: "-0.0",
+
+ Z3_OP_FPA_ADD: "+", Z3_OP_FPA_SUB: "-", Z3_OP_FPA_MUL: "*", Z3_OP_FPA_DIV: "/",
+ Z3_OP_FPA_REM: "%", Z3_OP_FPA_NEG: "-",
+
+ Z3_OP_FPA_EQ: "fpEQ", Z3_OP_FPA_LT: "<", Z3_OP_FPA_GT: ">", Z3_OP_FPA_LE: "<=", Z3_OP_FPA_GE: ">="
+}
+
_z3_fpa_infix = [
Z3_OP_FPA_ADD, Z3_OP_FPA_SUB, Z3_OP_FPA_MUL, Z3_OP_FPA_DIV, Z3_OP_FPA_REM,
Z3_OP_FPA_LT, Z3_OP_FPA_GT, Z3_OP_FPA_LE, Z3_OP_FPA_GE
]
+
+_ASSOC_OPS = frozenset({
+ Z3_OP_BOR,
+ Z3_OP_BXOR,
+ Z3_OP_BAND,
+ Z3_OP_ADD,
+ Z3_OP_BADD,
+ Z3_OP_MUL,
+ Z3_OP_BMUL,
+})
+
+
def _is_assoc(k):
- return k == Z3_OP_BOR or k == Z3_OP_BXOR or k == Z3_OP_BAND or k == Z3_OP_ADD or k == Z3_OP_BADD or k == Z3_OP_MUL or k == Z3_OP_BMUL
+ return k in _ASSOC_OPS
+
def _is_left_assoc(k):
return _is_assoc(k) or k == Z3_OP_SUB or k == Z3_OP_BSUB
+
def _is_html_assoc(k):
return k == Z3_OP_AND or k == Z3_OP_OR or k == Z3_OP_IFF or _is_assoc(k)
+
def _is_html_left_assoc(k):
return _is_html_assoc(k) or k == Z3_OP_SUB or k == Z3_OP_BSUB
+
def _is_add(k):
return k == Z3_OP_ADD or k == Z3_OP_BADD
+
def _is_sub(k):
return k == Z3_OP_SUB or k == Z3_OP_BSUB
-import sys
-if sys.version < '3':
+
+if sys.version_info.major < 3:
import codecs
+
def u(x):
return codecs.unicode_escape_decode(x)[0]
else:
def u(x):
return x
-_z3_infix_compact = [ Z3_OP_MUL, Z3_OP_BMUL, Z3_OP_POWER, Z3_OP_DIV, Z3_OP_IDIV, Z3_OP_MOD, Z3_OP_BSDIV, Z3_OP_BSMOD ]
+_z3_infix_compact = [Z3_OP_MUL, Z3_OP_BMUL, Z3_OP_POWER, Z3_OP_DIV, Z3_OP_IDIV, Z3_OP_MOD, Z3_OP_BSDIV, Z3_OP_BSMOD]
-_ellipses = '...'
+_ellipses = "..."
-_html_ellipses = '…'
+_html_ellipses = "…"
# Overwrite some of the operators for HTML
-_z3_pre_html_op_to_str = { Z3_OP_EQ : '=', Z3_OP_IFF : '=', Z3_OP_NOT : '¬',
- Z3_OP_AND : '∧', Z3_OP_OR : '∨', Z3_OP_IMPLIES : '⇒',
- Z3_OP_LT : '<', Z3_OP_GT : '>', Z3_OP_LE : '≤', Z3_OP_GE : '≥',
- Z3_OP_MUL : '·',
- Z3_OP_SLEQ : '≤', Z3_OP_SLT : '<', Z3_OP_SGEQ : '≥', Z3_OP_SGT : '>',
- Z3_OP_ULEQ : '≤u ', Z3_OP_ULT : '<u ',
- Z3_OP_UGEQ : '≥u ', Z3_OP_UGT : '>u ',
- Z3_OP_BMUL : '·',
- Z3_OP_BUDIV : '/u ', Z3_OP_BUREM : '%u ',
- Z3_OP_BASHR : '>>', Z3_OP_BSHL : '<<',
- Z3_OP_BLSHR : '>>u '
- }
+_z3_pre_html_op_to_str = {Z3_OP_EQ: "=", Z3_OP_IFF: "=", Z3_OP_NOT: "¬",
+ Z3_OP_AND: "∧", Z3_OP_OR: "∨", Z3_OP_IMPLIES: "⇒",
+ Z3_OP_LT: "<", Z3_OP_GT: ">", Z3_OP_LE: "≤", Z3_OP_GE: "≥",
+ Z3_OP_MUL: "·",
+ Z3_OP_SLEQ: "≤", Z3_OP_SLT: "<", Z3_OP_SGEQ: "≥", Z3_OP_SGT: ">",
+ Z3_OP_ULEQ: "≤u ", Z3_OP_ULT: "<u ",
+ Z3_OP_UGEQ: "≥u ", Z3_OP_UGT: ">u ",
+ Z3_OP_BMUL: "·",
+ Z3_OP_BUDIV: "/u ", Z3_OP_BUREM: "%u ",
+ Z3_OP_BASHR: ">>", Z3_OP_BSHL: "<<",
+ Z3_OP_BLSHR: ">>u "
+ }
# Extra operators that are infix/unary for HTML
-_z3_html_infix = [ Z3_OP_AND, Z3_OP_OR, Z3_OP_IMPLIES,
- Z3_OP_ULEQ, Z3_OP_ULT, Z3_OP_UGEQ, Z3_OP_UGT, Z3_OP_BUDIV, Z3_OP_BUREM, Z3_OP_BLSHR
- ]
+_z3_html_infix = [Z3_OP_AND, Z3_OP_OR, Z3_OP_IMPLIES,
+ Z3_OP_ULEQ, Z3_OP_ULT, Z3_OP_UGEQ, Z3_OP_UGT, Z3_OP_BUDIV, Z3_OP_BUREM, Z3_OP_BLSHR
+ ]
-_z3_html_unary = [ Z3_OP_NOT ]
+_z3_html_unary = [Z3_OP_NOT]
# Extra Precedence for HTML
-_z3_pre_html_precedence = { Z3_OP_BUDIV : 2, Z3_OP_BUREM : 2,
- Z3_OP_BLSHR : 4,
- Z3_OP_ULEQ : 8, Z3_OP_ULT : 8,
- Z3_OP_UGEQ : 8, Z3_OP_UGT : 8,
- Z3_OP_ULEQ : 8, Z3_OP_ULT : 8,
- Z3_OP_UGEQ : 8, Z3_OP_UGT : 8,
- Z3_OP_NOT : 1,
- Z3_OP_AND : 10,
- Z3_OP_OR : 11,
- Z3_OP_IMPLIES : 12 }
+_z3_pre_html_precedence = {Z3_OP_BUDIV: 2, Z3_OP_BUREM: 2,
+ Z3_OP_BLSHR: 4,
+ Z3_OP_ULEQ: 8, Z3_OP_ULT: 8,
+ Z3_OP_UGEQ: 8, Z3_OP_UGT: 8,
+ Z3_OP_ULEQ: 8, Z3_OP_ULT: 8,
+ Z3_OP_UGEQ: 8, Z3_OP_UGT: 8,
+ Z3_OP_NOT: 1,
+ Z3_OP_AND: 10,
+ Z3_OP_OR: 11,
+ Z3_OP_IMPLIES: 12}
##############################
#
@@ -198,9 +312,11 @@ _z3_pre_html_precedence = { Z3_OP_BUDIV : 2, Z3_OP_BUREM : 2,
#
##############################
+
def _support_pp(a):
return isinstance(a, z3.Z3PPObject) or isinstance(a, list) or isinstance(a, tuple)
+
_infix_map = {}
_unary_map = {}
_infix_compact_map = {}
@@ -209,22 +325,26 @@ for _k in _z3_infix:
_infix_map[_k] = True
for _k in _z3_unary:
_unary_map[_k] = True
-
+
for _k in _z3_infix_compact:
_infix_compact_map[_k] = True
+
def _is_infix(k):
global _infix_map
return _infix_map.get(k, False)
+
def _is_infix_compact(k):
global _infix_compact_map
return _infix_compact_map.get(k, False)
+
def _is_unary(k):
global _unary_map
return _unary_map.get(k, False)
+
def _op_name(a):
if isinstance(a, z3.FuncDeclRef):
f = a
@@ -232,15 +352,17 @@ def _op_name(a):
f = a.decl()
k = f.kind()
n = _z3_op_to_str.get(k, None)
- if n == None:
+ if n is None:
return f.name()
else:
return n
+
def _get_precedence(k):
global _z3_precedence
return _z3_precedence.get(k, 100000)
+
_z3_html_op_to_str = {}
for _k in _z3_op_to_str:
_v = _z3_op_to_str[_k]
@@ -268,14 +390,17 @@ for _k in _z3_unary:
for _k in _z3_html_unary:
_html_unary_map[_k] = True
+
def _is_html_infix(k):
global _html_infix_map
return _html_infix_map.get(k, False)
+
def _is_html_unary(k):
global _html_unary_map
return _html_unary_map.get(k, False)
+
def _html_op_name(a):
global _z3_html_op_to_str
if isinstance(a, z3.FuncDeclRef):
@@ -284,7 +409,7 @@ def _html_op_name(a):
f = a.decl()
k = f.kind()
n = _z3_html_op_to_str.get(k, None)
- if n == None:
+ if n is None:
sym = Z3_get_decl_name(f.ctx_ref(), f.ast)
if Z3_get_symbol_kind(f.ctx_ref(), sym) == Z3_INT_SYMBOL:
return "ζ%s " % Z3_get_symbol_int(f.ctx_ref(), sym)
@@ -294,44 +419,60 @@ def _html_op_name(a):
else:
return n
+
def _get_html_precedence(k):
global _z3_html_predence
return _z3_html_precedence.get(k, 100000)
+
class FormatObject:
def is_compose(self):
return False
+
def is_choice(self):
return False
+
def is_indent(self):
return False
+
def is_string(self):
return False
+
def is_linebreak(self):
return False
+
def is_nil(self):
return True
+
def children(self):
return []
+
def as_tuple(self):
return None
+
def space_upto_nl(self):
return (0, False)
+
def flat(self):
return self
+
class NAryFormatObject(FormatObject):
def __init__(self, fs):
assert all([isinstance(a, FormatObject) for a in fs])
self.children = fs
+
def children(self):
return self.children
+
class ComposeFormatObject(NAryFormatObject):
def is_compose(sef):
return True
+
def as_tuple(self):
- return ('compose', [ a.as_tuple() for a in self.children ])
+ return ("compose", [a.as_tuple() for a in self.children])
+
def space_upto_nl(self):
r = 0
for child in self.children:
@@ -340,135 +481,168 @@ class ComposeFormatObject(NAryFormatObject):
if nl:
return (r, True)
return (r, False)
+
def flat(self):
- return compose([a.flat() for a in self.children ])
+ return compose([a.flat() for a in self.children])
+
class ChoiceFormatObject(NAryFormatObject):
def is_choice(sef):
return True
+
def as_tuple(self):
- return ('choice', [ a.as_tuple() for a in self.children ])
+ return ("choice", [a.as_tuple() for a in self.children])
+
def space_upto_nl(self):
return self.children[0].space_upto_nl()
+
def flat(self):
return self.children[0].flat()
+
class IndentFormatObject(FormatObject):
def __init__(self, indent, child):
assert isinstance(child, FormatObject)
self.indent = indent
- self.child = child
+ self.child = child
+
def children(self):
return [self.child]
+
def as_tuple(self):
- return ('indent', self.indent, self.child.as_tuple())
+ return ("indent", self.indent, self.child.as_tuple())
+
def space_upto_nl(self):
return self.child.space_upto_nl()
+
def flat(self):
return indent(self.indent, self.child.flat())
+
def is_indent(self):
return True
+
class LineBreakFormatObject(FormatObject):
def __init__(self):
- self.space = ' '
+ self.space = " "
+
def is_linebreak(self):
return True
+
def as_tuple(self):
- return ''
+ return ""
+
def space_upto_nl(self):
return (0, True)
+
def flat(self):
return to_format(self.space)
+
class StringFormatObject(FormatObject):
def __init__(self, string):
assert isinstance(string, str)
self.string = string
+
def is_string(self):
return True
+
def as_tuple(self):
return self.string
+
def space_upto_nl(self):
- return (getattr(self, 'size', len(self.string)), False)
+ return (getattr(self, "size", len(self.string)), False)
+
def fits(f, space_left):
s, nl = f.space_upto_nl()
return s <= space_left
+
def to_format(arg, size=None):
if isinstance(arg, FormatObject):
return arg
else:
r = StringFormatObject(str(arg))
- if size != None:
+ if size is not None:
r.size = size
return r
+
def compose(*args):
if len(args) == 1 and (isinstance(args[0], list) or isinstance(args[0], tuple)):
args = args[0]
return ComposeFormatObject(args)
+
def indent(i, arg):
return IndentFormatObject(i, arg)
+
def group(arg):
return ChoiceFormatObject([arg.flat(), arg])
+
def line_break():
return LineBreakFormatObject()
+
def _len(a):
if isinstance(a, StringFormatObject):
- return getattr(a, 'size', len(a.string))
+ return getattr(a, "size", len(a.string))
else:
return len(a)
-def seq(args, sep=',', space=True):
+
+def seq(args, sep=",", space=True):
nl = line_break()
if not space:
- nl.space = ''
+ nl.space = ""
r = []
r.append(args[0])
- num = len(args)
+ num = len(args)
for i in range(num - 1):
r.append(to_format(sep))
r.append(nl)
- r.append(args[i+1])
+ r.append(args[i + 1])
return compose(r)
-def seq1(header, args, lp='(', rp=')'):
+
+def seq1(header, args, lp="(", rp=")"):
return group(compose(to_format(header),
to_format(lp),
indent(len(lp) + _len(header),
seq(args)),
to_format(rp)))
-def seq2(header, args, i=4, lp='(', rp=')'):
+
+def seq2(header, args, i=4, lp="(", rp=")"):
if len(args) == 0:
return compose(to_format(header), to_format(lp), to_format(rp))
else:
return group(compose(indent(len(lp), compose(to_format(lp), to_format(header))),
indent(i, compose(seq(args), to_format(rp)))))
-def seq3(args, lp='(', rp=')'):
+
+def seq3(args, lp="(", rp=")"):
if len(args) == 0:
return compose(to_format(lp), to_format(rp))
else:
return group(indent(len(lp), compose(to_format(lp), seq(args), to_format(rp))))
+
class StopPPException(Exception):
def __str__(self):
- return 'pp-interrupted'
+ return "pp-interrupted"
+
class PP:
def __init__(self):
- self.max_lines = 200
- self.max_width = 60
- self.bounded = False
+ self.max_lines = 200
+ self.max_width = 60
+ self.bounded = False
self.max_indent = 40
-
+
def pp_string(self, f, indent):
if not self.bounded or self.pos <= self.max_width:
sz = _len(f)
@@ -489,17 +663,17 @@ class PP:
self.pp(f.children[0], indent)
else:
self.pp(f.children[1], indent)
-
+
def pp_line_break(self, f, indent):
self.pos = indent
self.ribbon_pos = 0
self.line = self.line + 1
- if self.line < self.max_lines:
- self.out.write(u('\n'))
+ if self.line < self.max_lines:
+ self.out.write(u("\n"))
for i in range(indent):
- self.out.write(u(' '))
+ self.out.write(u(" "))
else:
- self.out.write(u('\n...'))
+ self.out.write(u("\n..."))
raise StopPPException()
def pp(self, f, indent):
@@ -523,37 +697,38 @@ class PP:
self.pos = 0
self.ribbon_pos = 0
self.line = 0
- self.out = out
+ self.out = out
self.pp(f, 0)
except StopPPException:
return
-
+
+
class Formatter:
def __init__(self):
global _ellipses
- self.max_depth = 20
- self.max_args = 128
+ self.max_depth = 20
+ self.max_args = 128
self.rational_to_decimal = False
- self.precision = 10
- self.ellipses = to_format(_ellipses)
- self.max_visited = 10000
- self.fpa_pretty = True
-
+ self.precision = 10
+ self.ellipses = to_format(_ellipses)
+ self.max_visited = 10000
+ self.fpa_pretty = True
+
def pp_ellipses(self):
return self.ellipses
def pp_arrow(self):
- return ' ->'
+ return " ->"
def pp_unknown(self):
- return ''
-
+ return ""
+
def pp_name(self, a):
return to_format(_op_name(a))
def is_infix(self, a):
return _is_infix(a)
-
+
def is_unary(self, a):
return _is_unary(a)
@@ -564,24 +739,24 @@ class Formatter:
return _is_infix_compact(a)
def is_infix_unary(self, a):
- return self.is_infix(a) or self.is_unary(a)
+ return self.is_infix(a) or self.is_unary(a)
def add_paren(self, a):
- return compose(to_format('('), indent(1, a), to_format(')'))
-
+ return compose(to_format("("), indent(1, a), to_format(")"))
+
def pp_sort(self, s):
if isinstance(s, z3.ArraySortRef):
- return seq1('Array', (self.pp_sort(s.domain()), self.pp_sort(s.range())))
+ return seq1("Array", (self.pp_sort(s.domain()), self.pp_sort(s.range())))
elif isinstance(s, z3.BitVecSortRef):
- return seq1('BitVec', (to_format(s.size()), ))
+ return seq1("BitVec", (to_format(s.size()), ))
elif isinstance(s, z3.FPSortRef):
- return seq1('FPSort', (to_format(s.ebits()), to_format(s.sbits())))
+ return seq1("FPSort", (to_format(s.ebits()), to_format(s.sbits())))
elif isinstance(s, z3.ReSortRef):
- return seq1('ReSort', (self.pp_sort(s.basis()), ))
+ return seq1("ReSort", (self.pp_sort(s.basis()), ))
elif isinstance(s, z3.SeqSortRef):
if s.is_string():
return to_format("String")
- return seq1('Seq', (self.pp_sort(s.basis()), ))
+ return seq1("Seq", (self.pp_sort(s.basis()), ))
else:
return to_format(s.name())
@@ -597,7 +772,7 @@ class Formatter:
def pp_int(self, a):
return to_format(a.as_string())
-
+
def pp_rational(self, a):
if not self.rational_to_decimal:
return to_format(a.as_string())
@@ -617,53 +792,53 @@ class Formatter:
return to_format(a.as_string())
def pp_fprm_value(self, a):
- _z3_assert(z3.is_fprm_value(a), 'expected FPRMNumRef')
+ _z3_assert(z3.is_fprm_value(a), "expected FPRMNumRef")
if self.fpa_pretty and (a.decl().kind() in _z3_op_to_fpa_pretty_str):
return to_format(_z3_op_to_fpa_pretty_str.get(a.decl().kind()))
else:
return to_format(_z3_op_to_fpa_normal_str.get(a.decl().kind()))
def pp_fp_value(self, a):
- _z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch')
+ _z3_assert(isinstance(a, z3.FPNumRef), "type mismatch")
if not self.fpa_pretty:
r = []
if (a.isNaN()):
r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_NAN]))
- r.append(to_format('('))
+ r.append(to_format("("))
r.append(to_format(a.sort()))
- r.append(to_format(')'))
+ r.append(to_format(")"))
return compose(r)
elif (a.isInf()):
if (a.isNegative()):
r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_MINUS_INF]))
else:
- r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_PLUS_INF]))
- r.append(to_format('('))
+ r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_PLUS_INF]))
+ r.append(to_format("("))
r.append(to_format(a.sort()))
- r.append(to_format(')'))
+ r.append(to_format(")"))
return compose(r)
elif (a.isZero()):
if (a.isNegative()):
- return to_format('-zero')
+ return to_format("-zero")
else:
- return to_format('+zero')
+ return to_format("+zero")
else:
- _z3_assert(z3.is_fp_value(a), 'expecting FP num ast')
+ _z3_assert(z3.is_fp_value(a), "expecting FP num ast")
r = []
sgn = c_int(0)
sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn))
exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast, False)
sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast)
- r.append(to_format('FPVal('))
+ r.append(to_format("FPVal("))
if sgnb and sgn.value != 0:
- r.append(to_format('-'))
+ r.append(to_format("-"))
r.append(to_format(sig))
- r.append(to_format('*(2**'))
+ r.append(to_format("*(2**"))
r.append(to_format(exp))
- r.append(to_format(', '))
+ r.append(to_format(", "))
r.append(to_format(a.sort()))
- r.append(to_format('))'))
+ r.append(to_format("))"))
return compose(r)
else:
if (a.isNaN()):
@@ -679,75 +854,74 @@ class Formatter:
else:
return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_PLUS_ZERO])
else:
- _z3_assert(z3.is_fp_value(a), 'expecting FP num ast')
+ _z3_assert(z3.is_fp_value(a), "expecting FP num ast")
r = []
sgn = (ctypes.c_int)(0)
sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn))
exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast, False)
sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast)
if sgnb and sgn.value != 0:
- r.append(to_format('-'))
+ r.append(to_format("-"))
r.append(to_format(sig))
- if (exp != '0'):
- r.append(to_format('*(2**'))
+ if (exp != "0"):
+ r.append(to_format("*(2**"))
r.append(to_format(exp))
- r.append(to_format(')'))
+ r.append(to_format(")"))
return compose(r)
-
def pp_fp(self, a, d, xs):
_z3_assert(isinstance(a, z3.FPRef), "type mismatch")
k = a.decl().kind()
- op = '?'
+ op = "?"
if (self.fpa_pretty and k in _z3_op_to_fpa_pretty_str):
op = _z3_op_to_fpa_pretty_str[k]
elif k in _z3_op_to_fpa_normal_str:
op = _z3_op_to_fpa_normal_str[k]
elif k in _z3_op_to_str:
- op = _z3_op_to_str[k]
+ op = _z3_op_to_str[k]
n = a.num_args()
if self.fpa_pretty:
- if self.is_infix(k) and n >= 3:
+ if self.is_infix(k) and n >= 3:
rm = a.arg(0)
if z3.is_fprm_value(rm) and z3.get_default_rounding_mode(a.ctx).eq(rm):
- arg1 = to_format(self.pp_expr(a.arg(1), d+1, xs))
- arg2 = to_format(self.pp_expr(a.arg(2), d+1, xs))
+ arg1 = to_format(self.pp_expr(a.arg(1), d + 1, xs))
+ arg2 = to_format(self.pp_expr(a.arg(2), d + 1, xs))
r = []
r.append(arg1)
- r.append(to_format(' '))
+ r.append(to_format(" "))
r.append(to_format(op))
- r.append(to_format(' '))
+ r.append(to_format(" "))
r.append(arg2)
return compose(r)
elif k == Z3_OP_FPA_NEG:
- return compose([to_format('-') , to_format(self.pp_expr(a.arg(0), d+1, xs))])
+ return compose([to_format("-"), to_format(self.pp_expr(a.arg(0), d + 1, xs))])
if k in _z3_op_to_fpa_normal_str:
op = _z3_op_to_fpa_normal_str[k]
-
- r = []
+
+ r = []
r.append(to_format(op))
if not z3.is_const(a):
- r.append(to_format('('))
+ r.append(to_format("("))
first = True
- for c in a.children():
+ for c in a.children():
if first:
first = False
else:
- r.append(to_format(', '))
- r.append(self.pp_expr(c, d+1, xs))
- r.append(to_format(')'))
+ r.append(to_format(", "))
+ r.append(self.pp_expr(c, d + 1, xs))
+ r.append(to_format(")"))
return compose(r)
else:
return to_format(a.as_string())
def pp_prefix(self, a, d, xs):
- r = []
+ r = []
sz = 0
- for child in a.children():
- r.append(self.pp_expr(child, d+1, xs))
+ for child in a.children():
+ r.append(self.pp_expr(child, d + 1, xs))
sz = sz + 1
if sz > self.max_args:
r.append(self.pp_ellipses())
@@ -762,11 +936,11 @@ class Formatter:
def infix_args_core(self, a, d, xs, r):
sz = len(r)
- k = a.decl().kind()
- p = self.get_precedence(k)
+ k = a.decl().kind()
+ p = self.get_precedence(k)
first = True
for child in a.children():
- child_pp = self.pp_expr(child, d+1, xs)
+ child_pp = self.pp_expr(child, d + 1, xs)
child_k = None
if z3.is_app(child):
child_k = child.decl().kind()
@@ -779,7 +953,7 @@ class Formatter:
child_p = self.get_precedence(child_k)
if p > child_p or (_is_add(k) and _is_sub(child_k)) or (_is_sub(k) and first and _is_add(child_k)):
r.append(child_pp)
- else:
+ else:
r.append(self.add_paren(child_pp))
sz = sz + 1
elif z3.is_quantifier(child):
@@ -798,25 +972,25 @@ class Formatter:
return r
def pp_infix(self, a, d, xs):
- k = a.decl().kind()
+ k = a.decl().kind()
if self.is_infix_compact(k):
op = self.pp_name(a)
return group(seq(self.infix_args(a, d, xs), op, False))
else:
op = self.pp_name(a)
sz = _len(op)
- op.string = ' ' + op.string
- op.size = sz + 1
+ op.string = " " + op.string
+ op.size = sz + 1
return group(seq(self.infix_args(a, d, xs), op))
def pp_unary(self, a, d, xs):
- k = a.decl().kind()
- p = self.get_precedence(k)
- child = a.children()[0]
- child_k = None
+ k = a.decl().kind()
+ p = self.get_precedence(k)
+ child = a.children()[0]
+ child_k = None
if z3.is_app(child):
child_k = child.decl().kind()
- child_pp = self.pp_expr(child, d+1, xs)
+ child_pp = self.pp_expr(child, d + 1, xs)
if k != child_k and self.is_infix_unary(child_k):
child_p = self.get_precedence(child_k)
if p <= child_p:
@@ -827,7 +1001,7 @@ class Formatter:
return compose(to_format(name), indent(_len(name), child_pp))
def pp_power_arg(self, arg, d, xs):
- r = self.pp_expr(arg, d+1, xs)
+ r = self.pp_expr(arg, d + 1, xs)
k = None
if z3.is_app(arg):
k = arg.decl().kind()
@@ -837,9 +1011,9 @@ class Formatter:
return r
def pp_power(self, a, d, xs):
- arg1_pp = self.pp_power_arg(a.arg(0), d+1, xs)
- arg2_pp = self.pp_power_arg(a.arg(1), d+1, xs)
- return group(seq((arg1_pp, arg2_pp), '**', False))
+ arg1_pp = self.pp_power_arg(a.arg(0), d + 1, xs)
+ arg2_pp = self.pp_power_arg(a.arg(1), d + 1, xs)
+ return group(seq((arg1_pp, arg2_pp), "**", False))
def pp_neq(self):
return to_format("!=")
@@ -848,8 +1022,8 @@ class Formatter:
if a.num_args() == 2:
op = self.pp_neq()
sz = _len(op)
- op.string = ' ' + op.string
- op.size = sz + 1
+ op.string = " " + op.string
+ op.size = sz + 1
return group(seq(self.infix_args(a, d, xs), op))
else:
return self.pp_prefix(a, d, xs)
@@ -858,28 +1032,28 @@ class Formatter:
if a.num_args() != 2:
return self.pp_prefix(a, d, xs)
else:
- arg1_pp = self.pp_expr(a.arg(0), d+1, xs)
- arg2_pp = self.pp_expr(a.arg(1), d+1, xs)
- return compose(arg1_pp, indent(2, compose(to_format('['), arg2_pp, to_format(']'))))
+ arg1_pp = self.pp_expr(a.arg(0), d + 1, xs)
+ arg2_pp = self.pp_expr(a.arg(1), d + 1, xs)
+ return compose(arg1_pp, indent(2, compose(to_format("["), arg2_pp, to_format("]"))))
def pp_unary_param(self, a, d, xs):
- p = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
- arg = self.pp_expr(a.arg(0), d+1, xs)
- return seq1(self.pp_name(a), [ to_format(p), arg ])
+ p = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
+ arg = self.pp_expr(a.arg(0), d + 1, xs)
+ return seq1(self.pp_name(a), [to_format(p), arg])
def pp_extract(self, a, d, xs):
- h = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
- l = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 1)
- arg = self.pp_expr(a.arg(0), d+1, xs)
- return seq1(self.pp_name(a), [ to_format(h), to_format(l), arg ])
+ high = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
+ low = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 1)
+ arg = self.pp_expr(a.arg(0), d + 1, xs)
+ return seq1(self.pp_name(a), [to_format(high), to_format(low), arg])
def pp_loop(self, a, d, xs):
- l = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
- arg = self.pp_expr(a.arg(0), d+1, xs)
+ low = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
+ arg = self.pp_expr(a.arg(0), d + 1, xs)
if Z3_get_decl_num_parameters(a.ctx_ref(), a.decl().ast) > 1:
- h = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 1)
- return seq1("Loop", [ arg, to_format(l), to_format(h) ])
- return seq1("Loop", [ arg, to_format(l) ])
+ high = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 1)
+ return seq1("Loop", [arg, to_format(low), to_format(high)])
+ return seq1("Loop", [arg, to_format(low)])
def pp_set(self, id, a):
return seq1(id, [self.pp_sort(a.sort())])
@@ -888,22 +1062,22 @@ class Formatter:
if a.num_args() == 1:
return self.pp_expr(a.arg(0), d, xs)
else:
- return seq1('MultiPattern', [ self.pp_expr(arg, d+1, xs) for arg in a.children() ])
+ return seq1("MultiPattern", [self.pp_expr(arg, d + 1, xs) for arg in a.children()])
def pp_is(self, a, d, xs):
- f = a.params()[0]
+ f = a.params()[0]
return self.pp_fdecl(f, a, d, xs)
def pp_map(self, a, d, xs):
- f = z3.get_map_func(a)
+ f = z3.get_map_func(a)
return self.pp_fdecl(f, a, d, xs)
def pp_fdecl(self, f, a, d, xs):
- r = []
+ r = []
sz = 0
r.append(to_format(f.name()))
- for child in a.children():
- r.append(self.pp_expr(child, d+1, xs))
+ for child in a.children():
+ r.append(self.pp_expr(child, d + 1, xs))
sz = sz + 1
if sz > self.max_args:
r.append(self.pp_ellipses())
@@ -911,28 +1085,27 @@ class Formatter:
return seq1(self.pp_name(a), r)
def pp_K(self, a, d, xs):
- return seq1(self.pp_name(a), [ self.pp_sort(a.domain()), self.pp_expr(a.arg(0), d+1, xs) ])
+ return seq1(self.pp_name(a), [self.pp_sort(a.domain()), self.pp_expr(a.arg(0), d + 1, xs)])
def pp_atmost(self, a, d, f, xs):
- k = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
- return seq1(self.pp_name(a), [seq3([ self.pp_expr(ch, d+1, xs) for ch in a.children()]), to_format(k)])
+ k = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
+ return seq1(self.pp_name(a), [seq3([self.pp_expr(ch, d + 1, xs) for ch in a.children()]), to_format(k)])
def pp_pbcmp(self, a, d, f, xs):
chs = a.children()
rchs = range(len(chs))
- k = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
- ks = [Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, i+1) for i in rchs]
- ls = [ seq3([self.pp_expr(chs[i], d+1,xs), to_format(ks[i])]) for i in rchs]
+ k = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0)
+ ks = [Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, i + 1) for i in rchs]
+ ls = [seq3([self.pp_expr(chs[i], d + 1, xs), to_format(ks[i])]) for i in rchs]
return seq1(self.pp_name(a), [seq3(ls), to_format(k)])
-
def pp_app(self, a, d, xs):
if z3.is_int_value(a):
return self.pp_int(a)
elif z3.is_rational_value(a):
return self.pp_rational(a)
elif z3.is_algebraic_value(a):
- return self.pp_algebraic(a)
+ return self.pp_algebraic(a)
elif z3.is_bv_value(a):
return self.pp_bv(a)
elif z3.is_finite_domain_value(a):
@@ -987,26 +1160,26 @@ class Formatter:
def pp_var(self, a, d, xs):
idx = z3.get_var_index(a)
- sz = len(xs)
+ sz = len(xs)
if idx >= sz:
- return seq1('Var', (to_format(idx),))
+ return seq1("Var", (to_format(idx),))
else:
return to_format(xs[sz - idx - 1])
-
+
def pp_quantifier(self, a, d, xs):
- ys = [ to_format(a.var_name(i)) for i in range(a.num_vars()) ]
- new_xs = xs + ys
- body_pp = self.pp_expr(a.body(), d+1, new_xs)
+ ys = [to_format(a.var_name(i)) for i in range(a.num_vars())]
+ new_xs = xs + ys
+ body_pp = self.pp_expr(a.body(), d + 1, new_xs)
if len(ys) == 1:
ys_pp = ys[0]
else:
- ys_pp = seq3(ys, '[', ']')
+ ys_pp = seq3(ys, "[", "]")
if a.is_forall():
- header = 'ForAll'
+ header = "ForAll"
elif a.is_exists():
- header = 'Exists'
+ header = "Exists"
else:
- header = 'Lambda'
+ header = "Lambda"
return seq1(header, (ys_pp, body_pp))
def pp_expr(self, a, d, xs):
@@ -1025,10 +1198,10 @@ class Formatter:
def pp_decl(self, f):
k = f.kind()
if k == Z3_OP_DT_IS or k == Z3_OP_ARRAY_MAP:
- g = f.params()[0]
- r = [ to_format(g.name()) ]
- return seq1(self.pp_name(f), r)
- return self.pp_name(f)
+ g = f.params()[0]
+ r = [to_format(g.name())]
+ return seq1(self.pp_name(f), r)
+ return self.pp_name(f)
def pp_seq_core(self, f, a, d, xs):
self.visited = self.visited + 1
@@ -1037,13 +1210,13 @@ class Formatter:
r = []
sz = 0
for elem in a:
- r.append(f(elem, d+1, xs))
+ r.append(f(elem, d + 1, xs))
sz = sz + 1
if sz > self.max_args:
r.append(self.pp_ellipses())
break
- return seq3(r, '[', ']')
-
+ return seq3(r, "[", "]")
+
def pp_seq(self, a, d, xs):
return self.pp_seq_core(self.pp_expr, a, d, xs)
@@ -1060,12 +1233,12 @@ class Formatter:
else:
i_pp = self.pp_expr(i, 0, [])
name = self.pp_name(d)
- r.append(compose(name, to_format(' = '), indent(_len(name) + 3, i_pp)))
+ r.append(compose(name, to_format(" = "), indent(_len(name) + 3, i_pp)))
sz = sz + 1
if sz > self.max_args:
r.append(self.pp_ellipses())
break
- return seq3(r, '[', ']')
+ return seq3(r, "[", "]")
def pp_func_entry(self, e):
num = e.num_args()
@@ -1075,8 +1248,8 @@ class Formatter:
args.append(self.pp_expr(e.arg_value(i), 0, []))
args_pp = group(seq3(args))
else:
- args_pp = self.pp_expr(e.arg_value(0), 0, [])
- value_pp = self.pp_expr(e.value(), 0, [])
+ args_pp = self.pp_expr(e.arg_value(0), 0, [])
+ value_pp = self.pp_expr(e.value(), 0, [])
return group(seq((args_pp, value_pp), self.pp_arrow()))
def pp_func_interp(self, f):
@@ -1091,12 +1264,12 @@ class Formatter:
break
if sz <= self.max_args:
else_val = f.else_value()
- if else_val == None:
- else_pp = to_format('#unspecified')
+ if else_val is None:
+ else_pp = to_format("#unspecified")
else:
- else_pp = self.pp_expr(else_val, 0, [])
- r.append(group(seq((to_format('else'), else_pp), self.pp_arrow())))
- return seq3(r, '[', ']')
+ else_pp = self.pp_expr(else_val, 0, [])
+ r.append(group(seq((to_format("else"), else_pp), self.pp_arrow())))
+ return seq3(r, "[", "]")
def pp_list(self, a):
r = []
@@ -1113,7 +1286,7 @@ class Formatter:
if isinstance(a, tuple):
return seq3(r)
else:
- return seq3(r, '[', ']')
+ return seq3(r, "[", "]")
def main(self, a):
if z3.is_expr(a):
@@ -1145,6 +1318,7 @@ class Formatter:
self.visited = 0
return self.main(a)
+
class HTMLFormatter(Formatter):
def __init__(self):
Formatter.__init__(self)
@@ -1152,17 +1326,17 @@ class HTMLFormatter(Formatter):
self.ellipses = to_format(_html_ellipses)
def pp_arrow(self):
- return to_format(' →', 1)
+ return to_format(" →", 1)
def pp_unknown(self):
- return 'unknown '
-
+ return "unknown "
+
def pp_name(self, a):
r = _html_op_name(a)
- if r[0] == '&' or r[0] == '/' or r[0] == '%':
+ if r[0] == "&" or r[0] == "/" or r[0] == "%":
return to_format(r, 1)
else:
- pos = r.find('__')
+ pos = r.find("__")
if pos == -1 or pos == 0:
return to_format(r)
else:
@@ -1170,7 +1344,7 @@ class HTMLFormatter(Formatter):
if pos + 2 == sz:
return to_format(r)
else:
- return to_format('%s%s ' % (r[0:pos], r[pos+2:sz]), sz - 2)
+ return to_format("%s%s " % (r[0:pos], r[pos + 2:sz]), sz - 2)
def is_assoc(self, k):
return _is_html_assoc(k)
@@ -1180,7 +1354,7 @@ class HTMLFormatter(Formatter):
def is_infix(self, a):
return _is_html_infix(a)
-
+
def is_unary(self, a):
return _is_html_unary(a)
@@ -1191,67 +1365,71 @@ class HTMLFormatter(Formatter):
return to_format("≠")
def pp_power(self, a, d, xs):
- arg1_pp = self.pp_power_arg(a.arg(0), d+1, xs)
- arg2_pp = self.pp_expr(a.arg(1), d+1, xs)
- return compose(arg1_pp, to_format('', 1), arg2_pp, to_format(' ', 1))
+ arg1_pp = self.pp_power_arg(a.arg(0), d + 1, xs)
+ arg2_pp = self.pp_expr(a.arg(1), d + 1, xs)
+ return compose(arg1_pp, to_format("", 1), arg2_pp, to_format(" ", 1))
def pp_var(self, a, d, xs):
idx = z3.get_var_index(a)
- sz = len(xs)
+ sz = len(xs)
if idx >= sz:
# 957 is the greek letter nu
- return to_format('ν%s ' % idx, 1)
+ return to_format("ν%s " % idx, 1)
else:
return to_format(xs[sz - idx - 1])
def pp_quantifier(self, a, d, xs):
- ys = [ to_format(a.var_name(i)) for i in range(a.num_vars()) ]
- new_xs = xs + ys
- body_pp = self.pp_expr(a.body(), d+1, new_xs)
+ ys = [to_format(a.var_name(i)) for i in range(a.num_vars())]
+ new_xs = xs + ys
+ body_pp = self.pp_expr(a.body(), d + 1, new_xs)
ys_pp = group(seq(ys))
if a.is_forall():
- header = '∀'
+ header = "∀"
else:
- header = '∃'
- return group(compose(to_format(header, 1),
- indent(1, compose(ys_pp, to_format(' :'), line_break(), body_pp))))
+ header = "∃"
+ return group(compose(to_format(header, 1),
+ indent(1, compose(ys_pp, to_format(" :"), line_break(), body_pp))))
-_PP = PP()
+_PP = PP()
_Formatter = Formatter()
+
def set_pp_option(k, v):
- if k == 'html_mode':
+ if k == "html_mode":
if v:
set_html_mode(True)
else:
set_html_mode(False)
return True
- if k == 'fpa_pretty':
+ if k == "fpa_pretty":
if v:
set_fpa_pretty(True)
else:
set_fpa_pretty(False)
return True
val = getattr(_PP, k, None)
- if val != None:
- _z3_assert(type(v) == type(val), "Invalid pretty print option value")
+ if val is not None:
+ _z3_assert(isinstance(v, type(val)), "Invalid pretty print option value")
setattr(_PP, k, v)
return True
val = getattr(_Formatter, k, None)
- if val != None:
- _z3_assert(type(v) == type(val), "Invalid pretty print option value")
+ if val is not None:
+ _z3_assert(isinstance(v, type(val)), "Invalid pretty print option value")
setattr(_Formatter, k, v)
return True
return False
+
def obj_to_string(a):
out = io.StringIO()
_PP(out, _Formatter(a))
return out.getvalue()
+
_html_out = None
+
def set_html_mode(flag=True):
global _Formatter
if flag:
@@ -1259,36 +1437,42 @@ def set_html_mode(flag=True):
else:
_Formatter = Formatter()
+
def set_fpa_pretty(flag=True):
global _Formatter
global _z3_op_to_str
_Formatter.fpa_pretty = flag
if flag:
- for (_k,_v) in _z3_op_to_fpa_pretty_str.items():
+ for (_k, _v) in _z3_op_to_fpa_pretty_str.items():
_z3_op_to_str[_k] = _v
for _k in _z3_fpa_infix:
_infix_map[_k] = True
else:
- for (_k,_v) in _z3_op_to_fpa_normal_str.items():
+ for (_k, _v) in _z3_op_to_fpa_normal_str.items():
_z3_op_to_str[_k] = _v
for _k in _z3_fpa_infix:
_infix_map[_k] = False
+
set_fpa_pretty(True)
+
def get_fpa_pretty():
global Formatter
return _Formatter.fpa_pretty
+
def in_html_mode():
return isinstance(_Formatter, HTMLFormatter)
+
def pp(a):
if _support_pp(a):
print(obj_to_string(a))
else:
print(a)
+
def print_matrix(m):
_z3_assert(isinstance(m, list) or isinstance(m, tuple), "matrix expected")
if not in_html_mode():
@@ -1297,12 +1481,13 @@ def print_matrix(m):
print('')
for r in m:
_z3_assert(isinstance(r, list) or isinstance(r, tuple), "matrix expected")
- print('')
+ print(" ")
for c in r:
- print('%s ' % c)
- print(' ')
- print('
')
-
+ print("%s " % c)
+ print("")
+ print("")
+
+
def insert_line_breaks(s, width):
"""Break s in lines of size width (approx)"""
sz = len(s)
@@ -1311,8 +1496,8 @@ def insert_line_breaks(s, width):
new_str = io.StringIO()
w = 0
for i in range(sz):
- if w > width and s[i] == ' ':
- new_str.write(u(' '))
+ if w > width and s[i] == " ":
+ new_str.write(u(" "))
w = 0
else:
new_str.write(u(s[i]))
diff --git a/src/api/python/z3/z3rcf.py b/src/api/python/z3/z3rcf.py
index 76d22bbca..019e372e2 100644
--- a/src/api/python/z3/z3rcf.py
+++ b/src/api/python/z3/z3rcf.py
@@ -1,8 +1,8 @@
############################################
# Copyright (c) 2013 Microsoft Corporation
-#
+#
# Z3 Python interface for Z3 Real Closed Fields
-# that may contain
+# that may contain
# - computable transcendentals
# - infinitesimals
# - algebraic extensions
@@ -12,7 +12,7 @@
from .z3 import *
from .z3core import *
from .z3printer import *
-from fractions import Fraction
+
def _to_rcfnum(num, ctx=None):
if isinstance(num, RCFNum):
@@ -20,36 +20,41 @@ def _to_rcfnum(num, ctx=None):
else:
return RCFNum(num, ctx)
+
def Pi(ctx=None):
ctx = z3.get_ctx(ctx)
return RCFNum(Z3_rcf_mk_pi(ctx.ref()), ctx)
+
def E(ctx=None):
ctx = z3.get_ctx(ctx)
return RCFNum(Z3_rcf_mk_e(ctx.ref()), ctx)
+
def MkInfinitesimal(name="eps", ctx=None):
# Todo: remove parameter name.
# For now, we keep it for backward compatibility.
ctx = z3.get_ctx(ctx)
return RCFNum(Z3_rcf_mk_infinitesimal(ctx.ref()), ctx)
+
def MkRoots(p, ctx=None):
ctx = z3.get_ctx(ctx)
num = len(p)
- _tmp = []
- _as = (RCFNumObj * num)()
- _rs = (RCFNumObj * num)()
+ _tmp = []
+ _as = (RCFNumObj * num)()
+ _rs = (RCFNumObj * num)()
for i in range(num):
_a = _to_rcfnum(p[i], ctx)
- _tmp.append(_a) # prevent GC
+ _tmp.append(_a) # prevent GC
_as[i] = _a.num
nr = Z3_rcf_mk_roots(ctx.ref(), num, _as, _rs)
- r = []
+ r = []
for i in range(nr):
r.append(RCFNum(_rs[i], ctx))
return r
+
class RCFNum:
def __init__(self, num, ctx=None):
# TODO: add support for converting AST numeral values into RCFNum
@@ -65,7 +70,7 @@ class RCFNum:
def ctx_ref(self):
return self.ctx.ref()
-
+
def __repr__(self):
return Z3_rcf_num_to_string(self.ctx_ref(), self.num, False, in_html_mode())
@@ -112,10 +117,10 @@ class RCFNum:
def __pow__(self, k):
return self.power(k)
-
+
def decimal(self, prec=5):
return Z3_rcf_num_to_decimal_string(self.ctx_ref(), self.num, prec)
-
+
def __lt__(self, other):
v = _to_rcfnum(other, self.ctx)
return Z3_rcf_lt(self.ctx_ref(), self.num, v.num)
diff --git a/src/api/python/z3/z3types.py b/src/api/python/z3/z3types.py
index 5c93b27a2..6c93c0bee 100644
--- a/src/api/python/z3/z3types.py
+++ b/src/api/python/z3/z3types.py
@@ -1,6 +1,6 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
+#
# Z3 Python interface
#
# Author: Leonardo de Moura (leonardo)
@@ -8,123 +8,234 @@
import ctypes
+
class Z3Exception(Exception):
def __init__(self, value):
self.value = value
+
def __str__(self):
return str(self.value)
+
class ContextObj(ctypes.c_void_p):
- def __init__(self, context): self._as_parameter_ = context
- def from_param(obj): return obj
+ def __init__(self, context):
+ self._as_parameter_ = context
+
+ def from_param(obj):
+ return obj
+
class Config(ctypes.c_void_p):
- def __init__(self, config): self._as_parameter_ = config
- def from_param(obj): return obj
+ def __init__(self, config):
+ self._as_parameter_ = config
+
+ def from_param(obj):
+ return obj
+
class Symbol(ctypes.c_void_p):
- def __init__(self, symbol): self._as_parameter_ = symbol
- def from_param(obj): return obj
+ def __init__(self, symbol):
+ self._as_parameter_ = symbol
+
+ def from_param(obj):
+ return obj
+
class Sort(ctypes.c_void_p):
- def __init__(self, sort): self._as_parameter_ = sort
- def from_param(obj): return obj
+ def __init__(self, sort):
+ self._as_parameter_ = sort
+
+ def from_param(obj):
+ return obj
+
class FuncDecl(ctypes.c_void_p):
- def __init__(self, decl): self._as_parameter_ = decl
- def from_param(obj): return obj
+ def __init__(self, decl):
+ self._as_parameter_ = decl
+
+ def from_param(obj):
+ return obj
+
class Ast(ctypes.c_void_p):
- def __init__(self, ast): self._as_parameter_ = ast
- def from_param(obj): return obj
+ def __init__(self, ast):
+ self._as_parameter_ = ast
+
+ def from_param(obj):
+ return obj
+
class Pattern(ctypes.c_void_p):
- def __init__(self, pattern): self._as_parameter_ = pattern
- def from_param(obj): return obj
+ def __init__(self, pattern):
+ self._as_parameter_ = pattern
+
+ def from_param(obj):
+ return obj
+
class Model(ctypes.c_void_p):
- def __init__(self, model): self._as_parameter_ = model
- def from_param(obj): return obj
+ def __init__(self, model):
+ self._as_parameter_ = model
+
+ def from_param(obj):
+ return obj
+
class Literals(ctypes.c_void_p):
- def __init__(self, literals): self._as_parameter_ = literals
- def from_param(obj): return obj
+ def __init__(self, literals):
+ self._as_parameter_ = literals
+
+ def from_param(obj):
+ return obj
+
class Constructor(ctypes.c_void_p):
- def __init__(self, constructor): self._as_parameter_ = constructor
- def from_param(obj): return obj
+ def __init__(self, constructor):
+ self._as_parameter_ = constructor
+
+ def from_param(obj):
+ return obj
+
class ConstructorList(ctypes.c_void_p):
- def __init__(self, constructor_list): self._as_parameter_ = constructor_list
- def from_param(obj): return obj
+ def __init__(self, constructor_list):
+ self._as_parameter_ = constructor_list
+
+ def from_param(obj):
+ return obj
+
class GoalObj(ctypes.c_void_p):
- def __init__(self, goal): self._as_parameter_ = goal
- def from_param(obj): return obj
+ def __init__(self, goal):
+ self._as_parameter_ = goal
+
+ def from_param(obj):
+ return obj
+
class TacticObj(ctypes.c_void_p):
- def __init__(self, tactic): self._as_parameter_ = tactic
- def from_param(obj): return obj
+ def __init__(self, tactic):
+ self._as_parameter_ = tactic
+
+ def from_param(obj):
+ return obj
+
class ProbeObj(ctypes.c_void_p):
- def __init__(self, probe): self._as_parameter_ = probe
- def from_param(obj): return obj
+ def __init__(self, probe):
+ self._as_parameter_ = probe
+
+ def from_param(obj):
+ return obj
+
class ApplyResultObj(ctypes.c_void_p):
- def __init__(self, obj): self._as_parameter_ = obj
- def from_param(obj): return obj
+ def __init__(self, obj):
+ self._as_parameter_ = obj
+
+ def from_param(obj):
+ return obj
+
class StatsObj(ctypes.c_void_p):
- def __init__(self, statistics): self._as_parameter_ = statistics
- def from_param(obj): return obj
+ def __init__(self, statistics):
+ self._as_parameter_ = statistics
+
+ def from_param(obj):
+ return obj
+
class SolverObj(ctypes.c_void_p):
- def __init__(self, solver): self._as_parameter_ = solver
- def from_param(obj): return obj
+ def __init__(self, solver):
+ self._as_parameter_ = solver
+
+ def from_param(obj):
+ return obj
+
class SolverCallbackObj(ctypes.c_void_p):
- def __init__(self, solver): self._as_parameter_ = solver
- def from_param(obj): return obj
+ def __init__(self, solver):
+ self._as_parameter_ = solver
+
+ def from_param(obj):
+ return obj
+
class FixedpointObj(ctypes.c_void_p):
- def __init__(self, fixedpoint): self._as_parameter_ = fixedpoint
- def from_param(obj): return obj
+ def __init__(self, fixedpoint):
+ self._as_parameter_ = fixedpoint
+
+ def from_param(obj):
+ return obj
+
class OptimizeObj(ctypes.c_void_p):
- def __init__(self, optimize): self._as_parameter_ = optimize
- def from_param(obj): return obj
+ def __init__(self, optimize):
+ self._as_parameter_ = optimize
+
+ def from_param(obj):
+ return obj
+
class ModelObj(ctypes.c_void_p):
- def __init__(self, model): self._as_parameter_ = model
- def from_param(obj): return obj
+ def __init__(self, model):
+ self._as_parameter_ = model
+
+ def from_param(obj):
+ return obj
+
class AstVectorObj(ctypes.c_void_p):
- def __init__(self, vector): self._as_parameter_ = vector
- def from_param(obj): return obj
+ def __init__(self, vector):
+ self._as_parameter_ = vector
+
+ def from_param(obj):
+ return obj
+
class AstMapObj(ctypes.c_void_p):
- def __init__(self, ast_map): self._as_parameter_ = ast_map
- def from_param(obj): return obj
+ def __init__(self, ast_map):
+ self._as_parameter_ = ast_map
+
+ def from_param(obj):
+ return obj
+
class Params(ctypes.c_void_p):
- def __init__(self, params): self._as_parameter_ = params
- def from_param(obj): return obj
+ def __init__(self, params):
+ self._as_parameter_ = params
+
+ def from_param(obj):
+ return obj
+
class ParamDescrs(ctypes.c_void_p):
- def __init__(self, paramdescrs): self._as_parameter_ = paramdescrs
- def from_param(obj): return obj
+ def __init__(self, paramdescrs):
+ self._as_parameter_ = paramdescrs
+
+ def from_param(obj):
+ return obj
+
class FuncInterpObj(ctypes.c_void_p):
- def __init__(self, f): self._as_parameter_ = f
- def from_param(obj): return obj
+ def __init__(self, f):
+ self._as_parameter_ = f
+
+ def from_param(obj):
+ return obj
+
class FuncEntryObj(ctypes.c_void_p):
- def __init__(self, e): self._as_parameter_ = e
- def from_param(obj): return obj
+ def __init__(self, e):
+ self._as_parameter_ = e
+
+ def from_param(obj):
+ return obj
+
class RCFNumObj(ctypes.c_void_p):
- def __init__(self, e): self._as_parameter_ = e
- def from_param(obj): return obj
+ def __init__(self, e):
+ self._as_parameter_ = e
-
-
+ def from_param(obj):
+ return obj
diff --git a/src/api/python/z3/z3util.py b/src/api/python/z3/z3util.py
index b37d6b649..071e2b60e 100644
--- a/src/api/python/z3/z3util.py
+++ b/src/api/python/z3/z3util.py
@@ -1,21 +1,22 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
+#
# Z3 Python interface
#
# Authors: Leonardo de Moura (leonardo)
# ThanhVu (Vu) Nguyen
############################################
"""
-Usage:
+Usage:
import common_z3 as CM_Z3
"""
import ctypes
from .z3 import *
+
def vset(seq, idfun=None, as_list=True):
- # This functions preserves the order of arguments while removing duplicates.
+ # This functions preserves the order of arguments while removing duplicates.
# This function is from https://code.google.com/p/common-python-vu/source/browse/vu_common.py
# (Thanhu's personal code). It has been copied here to avoid a dependency on vu_common.py.
"""
@@ -24,36 +25,36 @@ def vset(seq, idfun=None, as_list=True):
>>> vset([[11,2],1, [10,['9',1]],2, 1, [11,2],[3,3],[10,99],1,[10,['9',1]]],idfun=repr)
[[11, 2], 1, [10, ['9', 1]], 2, [3, 3], [10, 99]]
"""
-
+
def _uniq_normal(seq):
d_ = {}
for s in seq:
if s not in d_:
d_[s] = None
yield s
-
- def _uniq_idfun(seq,idfun):
+
+ def _uniq_idfun(seq, idfun):
d_ = {}
for s in seq:
h_ = idfun(s)
if h_ not in d_:
d_[h_] = None
yield s
-
+
if idfun is None:
res = _uniq_normal(seq)
- else:
- res = _uniq_idfun(seq,idfun)
-
- return list(res) if as_list else res
+ else:
+ res = _uniq_idfun(seq, idfun)
+
+ return list(res) if as_list else res
def get_z3_version(as_str=False):
major = ctypes.c_uint(0)
minor = ctypes.c_uint(0)
build = ctypes.c_uint(0)
- rev = ctypes.c_uint(0)
- Z3_get_version(major,minor, build, rev)
+ rev = ctypes.c_uint(0)
+ Z3_get_version(major, minor, build, rev)
rs = map(int, (major.value, minor.value, build.value, rev.value))
if as_str:
return "{}.{}.{}.{}".format(*rs)
@@ -64,9 +65,9 @@ def get_z3_version(as_str=False):
def ehash(v):
"""
Returns a 'stronger' hash value than the default hash() method.
- The result from hash() is not enough to distinguish between 2
+ The result from hash() is not enough to distinguish between 2
z3 expressions in some cases.
-
+
Note: the following doctests will fail with Python 2.x as the
default formatting doesn't match that of 3.x.
>>> x1 = Bool('x'); x2 = Bool('x'); x3 = Int('x')
@@ -74,7 +75,7 @@ def ehash(v):
783810685 783810685 783810685
>>> print(ehash(x1), ehash(x2), ehash(x3))
x_783810685_1 x_783810685_1 x_783810685_2
-
+
"""
if z3_debug():
assert is_expr(v)
@@ -83,10 +84,11 @@ def ehash(v):
"""
-In Z3, variables are called *uninterpreted* consts and
+In Z3, variables are called *uninterpreted* consts and
variables are *interpreted* consts.
"""
+
def is_expr_var(v):
"""
EXAMPLES:
@@ -111,7 +113,8 @@ def is_expr_var(v):
True
"""
- return is_const(v) and v.decl().kind()==Z3_OP_UNINTERPRETED
+ return is_const(v) and v.decl().kind() == Z3_OP_UNINTERPRETED
+
def is_expr_val(v):
"""
@@ -135,13 +138,11 @@ def is_expr_val(v):
False
>>> is_expr_val(SafetyInjection)
False
- """
- return is_const(v) and v.decl().kind()!=Z3_OP_UNINTERPRETED
+ """
+ return is_const(v) and v.decl().kind() != Z3_OP_UNINTERPRETED
-
-
-def get_vars(f, rs = None):
+def get_vars(f, rs=None):
"""
>>> x,y = Ints('x y')
>>> a,b = Bools('a b')
@@ -151,15 +152,15 @@ def get_vars(f, rs = None):
"""
if rs is None:
rs = []
-
+
if z3_debug():
assert is_expr(f)
if is_const(f):
if is_expr_val(f):
return rs
- else: #variable
- return vset(rs + [f],str)
+ else: # variable
+ return vset(rs + [f], str)
else:
for f_ in f.children():
@@ -168,7 +169,6 @@ def get_vars(f, rs = None):
return vset(rs, str)
-
def mk_var(name, vsort):
if vsort.kind() == Z3_INT_SORT:
v = Int(name)
@@ -179,13 +179,12 @@ def mk_var(name, vsort):
elif vsort.kind() == Z3_DATATYPE_SORT:
v = Const(name, vsort)
else:
- raise TypeError('Cannot handle this sort (s: %sid: %d)' %(vsort,vsort.kind()))
-
+ raise TypeError("Cannot handle this sort (s: %sid: %d)" % (vsort, vsort.kind()))
+
return v
-
-def prove(claim,assume=None,verbose=0):
+def prove(claim, assume=None, verbose=0):
"""
>>> r,m = prove(BoolVal(True),verbose=0); r,model_str(m,as_str=False)
(True, None)
@@ -204,11 +203,11 @@ def prove(claim,assume=None,verbose=0):
AssertionError: Assumption is always False!
>>> r,m = prove(Implies(x,x),assume=y,verbose=2); r,model_str(m,as_str=False)
- assume:
+ assume:
y
- claim:
+ claim:
Implies(x, x)
- to_prove:
+ to_prove:
Implies(y, Implies(x, x))
(True, None)
@@ -236,52 +235,52 @@ def prove(claim,assume=None,verbose=0):
to_prove = claim
if assume:
if z3_debug():
- is_proved,_ = prove(Not(assume))
+ is_proved, _ = prove(Not(assume))
def _f():
emsg = "Assumption is always False!"
if verbose >= 2:
- emsg = "{}\n{}".format(assume,emsg)
+ emsg = "{}\n{}".format(assume, emsg)
return emsg
- assert is_proved==False, _f()
+ assert is_proved is False, _f()
- to_prove = Implies(assume,to_prove)
+ to_prove = Implies(assume, to_prove)
if verbose >= 2:
- print('assume: ')
+ print("assume: ")
print(assume)
- print('claim: ')
+ print("claim: ")
print(claim)
- print('to_prove: ')
+ print("to_prove: ")
print(to_prove)
f = Not(to_prove)
- models = get_models(f,k=1)
- if models is None: #unknown
- print('E: cannot solve !')
+ models = get_models(f, k=1)
+ if models is None: # unknown
+ print("E: cannot solve !")
return None, None
- elif models == False: #unsat
- return True,None
- else: #sat
+ elif models is False: # unsat
+ return True, None
+ else: # sat
if z3_debug():
- assert isinstance(models,list)
+ assert isinstance(models, list)
if models:
- return False, models[0] #the first counterexample
+ return False, models[0] # the first counterexample
else:
- return False, [] #infinite counterexample,models
-
+ return False, [] # infinite counterexample,models
-def get_models(f,k):
+
+def get_models(f, k):
"""
Returns the first k models satisfiying f.
If f is not satisfiable, returns False.
If f cannot be solved, returns None
If f is satisfiable, returns the first k models
- Note that if f is a tautology, e.g.\ True, then the result is []
-
+ Note that if f is a tautology, e.g.\\ True, then the result is []
+
Based on http://stackoverflow.com/questions/11867611/z3py-checking-all-solutions-for-equation
EXAMPLES:
@@ -314,7 +313,7 @@ def get_models(f,k):
if z3_debug():
assert is_expr(f)
assert k >= 1
-
+
s = Solver()
s.add(f)
@@ -323,16 +322,14 @@ def get_models(f,k):
while s.check() == sat and i < k:
i = i + 1
m = s.model()
- if not m: #if m == []
+ if not m: # if m == []
break
models.append(m)
-
- #create new constraint to block the current model
+ # create new constraint to block the current model
block = Not(And([v() == m[v] for v in m]))
s.add(block)
-
if s.check() == unknown:
return None
elif s.check() == unsat and i == 0:
@@ -340,7 +337,8 @@ def get_models(f,k):
else:
return models
-def is_tautology(claim,verbose=0):
+
+def is_tautology(claim, verbose=0):
"""
>>> is_tautology(Implies(Bool('x'),Bool('x')))
True
@@ -355,38 +353,38 @@ def is_tautology(claim,verbose=0):
False
"""
- return prove(claim=claim,assume=None,verbose=verbose)[0]
+ return prove(claim=claim, assume=None, verbose=verbose)[0]
-def is_contradiction(claim,verbose=0):
+def is_contradiction(claim, verbose=0):
"""
>>> x,y=Bools('x y')
>>> is_contradiction(BoolVal(False))
True
-
+
>>> is_contradiction(BoolVal(True))
False
-
+
>>> is_contradiction(x)
False
-
+
>>> is_contradiction(Implies(x,y))
False
-
+
>>> is_contradiction(Implies(x,x))
False
-
+
>>> is_contradiction(And(x,Not(x)))
True
"""
- return prove(claim=Not(claim),assume=None,verbose=verbose)[0]
+ return prove(claim=Not(claim), assume=None, verbose=verbose)[0]
def exact_one_model(f):
"""
return True if f has exactly 1 model, False otherwise.
-
+
EXAMPLES:
>>> x, y = Ints('x y')
@@ -403,30 +401,29 @@ def exact_one_model(f):
False
"""
- models = get_models(f,k=2)
- if isinstance(models,list):
- return len(models)==1
+ models = get_models(f, k=2)
+ if isinstance(models, list):
+ return len(models) == 1
else:
return False
-
-
-def myBinOp(op,*L):
+
+def myBinOp(op, *L):
"""
>>> myAnd(*[Bool('x'),Bool('y')])
And(x, y)
-
+
>>> myAnd(*[Bool('x'),None])
x
-
+
>>> myAnd(*[Bool('x')])
x
-
+
>>> myAnd(*[])
-
+
>>> myAnd(Bool('x'),Bool('y'))
And(x, y)
-
+
>>> myAnd(*[Bool('x'),Bool('y')])
And(x, y)
@@ -435,7 +432,7 @@ def myBinOp(op,*L):
>>> myAnd((Bool('x'),Bool('y')))
And(x, y)
-
+
>>> myAnd(*[Bool('x'),Bool('y'),True])
Traceback (most recent call last):
...
@@ -444,59 +441,62 @@ def myBinOp(op,*L):
if z3_debug():
assert op == Z3_OP_OR or op == Z3_OP_AND or op == Z3_OP_IMPLIES
-
- if len(L)==1 and (isinstance(L[0],list) or isinstance(L[0],tuple)):
+
+ if len(L) == 1 and (isinstance(L[0], list) or isinstance(L[0], tuple)):
L = L[0]
if z3_debug():
- assert all(not isinstance(l,bool) for l in L)
+ assert all(not isinstance(val, bool) for val in L)
- L = [l for l in L if is_expr(l)]
+ L = [val for val in L if is_expr(val)]
if L:
- if len(L)==1:
+ if len(L) == 1:
return L[0]
- if op == Z3_OP_OR:
+ if op == Z3_OP_OR:
return Or(L)
if op == Z3_OP_AND:
- return And(L)
- return Implies(L[0],L[1])
+ return And(L)
+ return Implies(L[0], L[1])
else:
return None
def myAnd(*L):
- return myBinOp(Z3_OP_AND,*L)
+ return myBinOp(Z3_OP_AND, *L)
+
def myOr(*L):
- return myBinOp(Z3_OP_OR,*L)
+ return myBinOp(Z3_OP_OR, *L)
-def myImplies(a,b):
- return myBinOp(Z3_OP_IMPLIES,[a,b])
-
-Iff = lambda f: And(Implies(f[0],f[1]),Implies(f[1],f[0]))
+def myImplies(a, b):
+ return myBinOp(Z3_OP_IMPLIES, [a, b])
-def model_str(m,as_str=True):
+
+def Iff(f):
+ return And(Implies(f[0], f[1]), Implies(f[1], f[0]))
+
+
+def model_str(m, as_str=True):
"""
Returned a 'sorted' model (so that it's easier to see)
- The model is sorted by its key,
- e.g. if the model is y = 3 , x = 10, then the result is
+ The model is sorted by its key,
+ e.g. if the model is y = 3 , x = 10, then the result is
x = 10, y = 3
EXAMPLES:
- see doctest exampels from function prove()
+ see doctest exampels from function prove()
"""
if z3_debug():
- assert m is None or m == [] or isinstance(m,ModelRef)
+ assert m is None or m == [] or isinstance(m, ModelRef)
- if m :
- vs = [(v,m[v]) for v in m]
- vs = sorted(vs,key=lambda a,_: str(a))
+ if m:
+ vs = [(v, m[v]) for v in m]
+ vs = sorted(vs, key=lambda a, _: str(a))
if as_str:
- return '\n'.join(['{} = {}'.format(k,v) for (k,v) in vs])
+ return "\n".join(["{} = {}".format(k, v) for (k, v) in vs])
else:
return vs
else:
return str(m) if as_str else m
-
diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h
index a3f7e5a01..399aa76f2 100644
--- a/src/ast/arith_decl_plugin.h
+++ b/src/ast/arith_decl_plugin.h
@@ -433,6 +433,7 @@ public:
app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(arith_family_id, OP_ADD, arg1, arg2); }
app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(arith_family_id, OP_ADD, arg1, arg2, arg3); }
app * mk_add(expr_ref_vector const& args) const { return mk_add(args.size(), args.data()); }
+ app * mk_add(expr_ref_buffer const& args) const { return mk_add(args.size(), args.data()); }
app * mk_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(arith_family_id, OP_SUB, arg1, arg2); }
app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(arith_family_id, OP_SUB, num_args, args); }
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 82f0d0c86..c564acba3 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -38,39 +38,27 @@ Revision History:
// -----------------------------------
parameter::~parameter() {
- if (m_kind == PARAM_RATIONAL) {
- dealloc(m_rational);
+ if (auto p = std::get_if(&m_val)) {
+ dealloc(*p);
}
- if (m_kind == PARAM_ZSTRING) {
- dealloc(m_zstring);
+ if (auto p = std::get_if(&m_val)) {
+ dealloc(*p);
}
}
-parameter::parameter(parameter const& other) {
- m_kind = PARAM_INT;
- m_int = 0;
- *this = other;
-}
-
parameter& parameter::operator=(parameter const& other) {
if (this == &other) {
return *this;
}
- if (m_kind == PARAM_RATIONAL) {
- dealloc(m_rational);
+
+ this->~parameter();
+ m_val = other.m_val;
+
+ if (auto p = std::get_if(&m_val)) {
+ m_val = alloc(rational, **p);
}
- m_kind = other.m_kind;
- switch(other.m_kind) {
- case PARAM_INT: m_int = other.get_int(); break;
- case PARAM_AST: m_ast = other.get_ast(); break;
- case PARAM_SYMBOL: m_symbol = other.m_symbol; break;
- case PARAM_RATIONAL: m_rational = alloc(rational, other.get_rational()); break;
- case PARAM_DOUBLE: m_dval = other.m_dval; break;
- case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break;
- case PARAM_ZSTRING: m_zstring = alloc(zstring, other.get_zstring()); break;
- default:
- UNREACHABLE();
- break;
+ if (auto p = std::get_if(&m_val)) {
+ m_val = alloc(zstring, **p);
}
return *this;
}
@@ -95,45 +83,40 @@ void parameter::del_eh(ast_manager & m, family_id fid) {
}
bool parameter::operator==(parameter const & p) const {
- if (m_kind != p.m_kind) return false;
- switch(m_kind) {
- case PARAM_INT: return m_int == p.m_int;
- case PARAM_AST: return m_ast == p.m_ast;
- case PARAM_SYMBOL: return get_symbol() == p.get_symbol();
+ if (get_kind() != p.get_kind()) return false;
+ switch (get_kind()) {
case PARAM_RATIONAL: return get_rational() == p.get_rational();
- case PARAM_DOUBLE: return m_dval == p.m_dval;
- case PARAM_EXTERNAL: return m_ext_id == p.m_ext_id;
case PARAM_ZSTRING: return get_zstring() == p.get_zstring();
- default: UNREACHABLE(); return false;
+ default: return m_val == p.m_val;
}
}
unsigned parameter::hash() const {
unsigned b = 0;
- switch(m_kind) {
- case PARAM_INT: b = m_int; break;
- case PARAM_AST: b = m_ast->hash(); break;
+ switch (get_kind()) {
+ case PARAM_INT: b = get_int(); break;
+ case PARAM_AST: b = get_ast()->hash(); break;
case PARAM_SYMBOL: b = get_symbol().hash(); break;
case PARAM_RATIONAL: b = get_rational().hash(); break;
- case PARAM_DOUBLE: b = static_cast(m_dval); break;
+ case PARAM_DOUBLE: b = static_cast(get_double()); break;
case PARAM_ZSTRING: b = get_zstring().hash(); break;
- case PARAM_EXTERNAL: b = m_ext_id; break;
+ case PARAM_EXTERNAL: b = get_ext_id(); break;
}
- return (b << 2) | m_kind;
+ return b;
}
std::ostream& parameter::display(std::ostream& out) const {
- switch(m_kind) {
+ switch (get_kind()) {
case PARAM_INT: return out << get_int();
case PARAM_SYMBOL: return out << get_symbol();
case PARAM_RATIONAL: return out << get_rational();
- case PARAM_AST: return out << "#" << get_ast()->get_id();
- case PARAM_DOUBLE: return out << m_dval;
- case PARAM_EXTERNAL: return out << "@" << m_ext_id;
+ case PARAM_AST: return out << '#' << get_ast()->get_id();
+ case PARAM_DOUBLE: return out << get_double();
+ case PARAM_EXTERNAL: return out << '@' << get_ext_id();
case PARAM_ZSTRING: return out << get_zstring();
default:
UNREACHABLE();
- return out << "[invalid parameter]";
+ return out;
}
}
@@ -191,14 +174,6 @@ decl_info::decl_info(family_id family_id, decl_kind k, unsigned num_parameters,
m_private_parameters(private_params) {
}
-decl_info::decl_info(decl_info const& other) :
- m_family_id(other.m_family_id),
- m_kind(other.m_kind),
- m_parameters(other.m_parameters.size(), other.m_parameters.data()),
- m_private_parameters(other.m_private_parameters) {
-}
-
-
void decl_info::init_eh(ast_manager & m) {
for (parameter & p : m_parameters) {
p.init_eh(m);
diff --git a/src/ast/ast.h b/src/ast/ast.h
index cdf53d4b2..0fafc2a76 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -47,6 +47,7 @@ Revision History:
#include "util/z3_exception.h"
#include "util/dependency.h"
#include "util/rlimit.h"
+#include
#define RECYCLE_FREE_AST_INDICES
@@ -97,6 +98,7 @@ const family_id arith_family_id = 5;
*/
class parameter {
public:
+ // NOTE: these must be in the same order as the entries in the variant below
enum kind_t {
PARAM_INT,
PARAM_AST,
@@ -113,63 +115,50 @@ public:
PARAM_EXTERNAL
};
private:
- kind_t m_kind;
-
// It is not possible to use tag pointers, since symbols are already tagged.
- union {
- int m_int; // for PARAM_INT
- ast* m_ast; // for PARAM_AST
- symbol m_symbol; // for PARAM_SYMBOL
- rational* m_rational; // for PARAM_RATIONAL
- zstring* m_zstring; // for PARAM_ZSTRING
- double m_dval; // for PARAM_DOUBLE (remark: this is not used in float_decl_plugin)
- unsigned m_ext_id; // for PARAM_EXTERNAL
- };
+ std::variant<
+ int, // for PARAM_INT
+ ast*, // for PARAM_AST
+ symbol, // for PARAM_SYMBOL
+ zstring*, // for PARAM_ZSTRING
+ rational*, // for PARAM_RATIONAL
+ double, // for PARAM_DOUBLE (remark: this is not used in float_decl_plugin)
+ unsigned // for PARAM_EXTERNAL
+ > m_val;
public:
- parameter(): m_kind(PARAM_INT), m_int(0) {}
- explicit parameter(int val): m_kind(PARAM_INT), m_int(val) {}
- explicit parameter(unsigned val): m_kind(PARAM_INT), m_int(val) {}
- explicit parameter(ast * p): m_kind(PARAM_AST), m_ast(p) {}
- explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL), m_symbol(s) {}
- explicit parameter(rational const & r): m_kind(PARAM_RATIONAL), m_rational(alloc(rational, r)) {}
- explicit parameter(rational && r) : m_kind(PARAM_RATIONAL), m_rational(alloc(rational, std::move(r))) {}
- explicit parameter(zstring const& s): m_kind(PARAM_ZSTRING), m_zstring(alloc(zstring, s)) {}
- explicit parameter(zstring && s): m_kind(PARAM_ZSTRING), m_zstring(alloc(zstring, std::move(s))) {}
- explicit parameter(double d):m_kind(PARAM_DOUBLE), m_dval(d) {}
- explicit parameter(const char *s):m_kind(PARAM_SYMBOL), m_symbol(symbol(s)) {}
- explicit parameter(const std::string &s):m_kind(PARAM_SYMBOL), m_symbol(symbol(s)) {}
- explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {}
- parameter(parameter const&);
+ parameter() : m_val(0) {}
+ explicit parameter(int val): m_val(val) {}
+ explicit parameter(unsigned val): m_val((int)val) {}
+ explicit parameter(ast * p): m_val(p) {}
+ explicit parameter(symbol const & s): m_val(s) {}
+ explicit parameter(rational const & r): m_val(alloc(rational, r)) {}
+ explicit parameter(rational && r) : m_val(alloc(rational, std::move(r))) {}
+ explicit parameter(zstring const& s): m_val(alloc(zstring, s)) {}
+ explicit parameter(zstring && s): m_val(alloc(zstring, std::move(s))) {}
+ explicit parameter(double d): m_val(d) {}
+ explicit parameter(const char *s): m_val(symbol(s)) {}
+ explicit parameter(const std::string &s): m_val(symbol(s)) {}
+ explicit parameter(unsigned ext_id, bool): m_val(ext_id) {}
+ parameter(parameter const& other) { *this = other; }
- parameter(parameter && other) noexcept : m_kind(other.m_kind) {
- switch (other.m_kind) {
- case PARAM_INT: m_int = other.get_int(); break;
- case PARAM_AST: m_ast = other.get_ast(); break;
- case PARAM_SYMBOL: m_symbol = other.m_symbol; break;
- case PARAM_RATIONAL: m_rational = nullptr; std::swap(m_rational, other.m_rational); break;
- case PARAM_DOUBLE: m_dval = other.m_dval; break;
- case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break;
- case PARAM_ZSTRING: m_zstring = other.m_zstring; break;
- default:
- UNREACHABLE();
- break;
- }
+ parameter(parameter && other) noexcept : m_val(std::move(other.m_val)) {
+ other.m_val = 0;
}
~parameter();
parameter& operator=(parameter const& other);
- kind_t get_kind() const { return m_kind; }
- bool is_int() const { return m_kind == PARAM_INT; }
- bool is_ast() const { return m_kind == PARAM_AST; }
- bool is_symbol() const { return m_kind == PARAM_SYMBOL; }
- bool is_rational() const { return m_kind == PARAM_RATIONAL; }
- bool is_double() const { return m_kind == PARAM_DOUBLE; }
- bool is_external() const { return m_kind == PARAM_EXTERNAL; }
- bool is_zstring() const { return m_kind == PARAM_ZSTRING; }
+ kind_t get_kind() const { return static_cast(m_val.index()); }
+ bool is_int() const { return get_kind() == PARAM_INT; }
+ bool is_ast() const { return get_kind() == PARAM_AST; }
+ bool is_symbol() const { return get_kind() == PARAM_SYMBOL; }
+ bool is_rational() const { return get_kind() == PARAM_RATIONAL; }
+ bool is_double() const { return get_kind() == PARAM_DOUBLE; }
+ bool is_external() const { return get_kind() == PARAM_EXTERNAL; }
+ bool is_zstring() const { return get_kind() == PARAM_ZSTRING; }
bool is_int(int & i) const { return is_int() && (i = get_int(), true); }
bool is_ast(ast * & a) const { return is_ast() && (a = get_ast(), true); }
@@ -191,13 +180,13 @@ public:
*/
void del_eh(ast_manager & m, family_id fid);
- int get_int() const { SASSERT(is_int()); return m_int; }
- ast * get_ast() const { SASSERT(is_ast()); return m_ast; }
- symbol get_symbol() const { SASSERT(is_symbol()); return m_symbol; }
- rational const & get_rational() const { SASSERT(is_rational()); return *m_rational; }
- zstring const& get_zstring() const { SASSERT(is_zstring()); return *m_zstring; }
- double get_double() const { SASSERT(is_double()); return m_dval; }
- unsigned get_ext_id() const { SASSERT(is_external()); return m_ext_id; }
+ int get_int() const { return std::get(m_val); }
+ ast * get_ast() const { return std::get(m_val); }
+ symbol get_symbol() const { return std::get(m_val); }
+ rational const & get_rational() const { return *std::get(m_val); }
+ zstring const& get_zstring() const { return *std::get(m_val); }
+ double get_double() const { return std::get(m_val); }
+ unsigned get_ext_id() const { return std::get(m_val); }
bool operator==(parameter const & p) const;
bool operator!=(parameter const & p) const { return !operator==(p); }
@@ -225,12 +214,10 @@ void display_parameters(std::ostream & out, unsigned n, parameter const * p);
between symbols (family names) and the unique IDs.
*/
class family_manager {
- family_id m_next_id;
+ family_id m_next_id = 0;
symbol_table m_families;
svector m_names;
public:
- family_manager():m_next_id(0) {}
-
/**
\brief Return the family_id for s, a new id is created if !has_family(s)
@@ -280,8 +267,6 @@ public:
decl_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind,
unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_params = false);
- decl_info(decl_info const& other);
-
void init_eh(ast_manager & m);
void del_eh(ast_manager & m);
@@ -381,8 +366,7 @@ public:
unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_parameters = false):
decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) {
}
- sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) {
- }
+
sort_info(decl_info const& di, sort_size const& num_elements) :
decl_info(di), m_num_elements(num_elements) {}
@@ -1010,8 +994,8 @@ struct builtin_name {
*/
class decl_plugin {
protected:
- ast_manager * m_manager;
- family_id m_family_id;
+ ast_manager * m_manager = nullptr;
+ family_id m_family_id = null_family_id;
virtual void set_manager(ast_manager * m, family_id id) {
SASSERT(m_manager == nullptr);
@@ -1035,8 +1019,6 @@ protected:
friend class ast_manager;
public:
- decl_plugin():m_manager(nullptr), m_family_id(null_family_id) {}
-
virtual ~decl_plugin() {}
virtual void finalize() {}
@@ -1365,8 +1347,6 @@ class user_sort_plugin : public decl_plugin {
svector m_sort_names;
dictionary m_name2decl_kind;
public:
- user_sort_plugin() {}
-
sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override;
func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) override;
@@ -2461,7 +2441,6 @@ typedef obj_mark expr_mark;
class expr_sparse_mark {
obj_hashtable m_marked;
public:
- expr_sparse_mark() {}
bool is_marked(expr * n) const { return m_marked.contains(n); }
void mark(expr * n) { m_marked.insert(n); }
void mark(expr * n, bool flag) { if (flag) m_marked.insert(n); else m_marked.erase(n); }
@@ -2472,7 +2451,6 @@ template
class ast_fast_mark {
ptr_buffer m_to_unmark;
public:
- ast_fast_mark() {}
~ast_fast_mark() {
reset();
}
@@ -2614,7 +2592,6 @@ class scoped_mark : public ast_mark {
unsigned_vector m_lim;
public:
scoped_mark(ast_manager& m): m_stack(m) {}
- ~scoped_mark() override {}
void mark(ast * n, bool flag) override;
void reset() override;
void mark(ast * n);
@@ -2655,7 +2632,3 @@ struct parameter_pp {
inline std::ostream& operator<<(std::ostream& out, parameter_pp const& pp) {
return pp.m.display(out, pp.p);
}
-
-
-
-
diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp
index 7190d5bf9..72d39290e 100644
--- a/src/ast/datatype_decl_plugin.cpp
+++ b/src/ast/datatype_decl_plugin.cpp
@@ -1082,6 +1082,14 @@ namespace datatype {
return r;
}
+ bool util::is_recursive_array(sort* a) {
+ array_util autil(m);
+ if (!autil.is_array(a))
+ return false;
+ a = autil.get_array_range_rec(a);
+ return is_datatype(a) && is_recursive(a);
+ }
+
bool util::is_enum_sort(sort* s) {
if (!is_datatype(s)) {
return false;
@@ -1243,6 +1251,9 @@ namespace datatype {
defined together in the same mutually recursive definition.
*/
bool util::are_siblings(sort * s1, sort * s2) {
+ array_util autil(m);
+ s1 = autil.get_array_range_rec(s1);
+ s2 = autil.get_array_range_rec(s2);
if (!is_datatype(s1) || !is_datatype(s2)) {
return s1 == s2;
}
diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h
index 6ac438f16..90d49e449 100644
--- a/src/ast/datatype_decl_plugin.h
+++ b/src/ast/datatype_decl_plugin.h
@@ -105,7 +105,6 @@ namespace datatype {
class size {
unsigned m_ref{ 0 };
public:
- size() {}
virtual ~size() { }
void inc_ref() { ++m_ref; }
void dec_ref();
@@ -124,7 +123,6 @@ namespace datatype {
struct offset : public size {
sort_size m_offset;
offset(sort_size const& s): m_offset(s) {}
- ~offset() override {}
size* subst(obj_map& S) override { return this; }
sort_size eval(obj_map const& S) override { return m_offset; }
};
@@ -152,7 +150,6 @@ namespace datatype {
struct sparam : public size {
sort_ref m_param;
sparam(sort_ref& p): m_param(p) {}
- ~sparam() override {}
size* subst(obj_map& S) override;
sort_size eval(obj_map const& S) override { return S[m_param]; }
};
@@ -333,6 +330,7 @@ namespace datatype {
bool is_datatype(sort const* s) const { return is_sort_of(s, fid(), DATATYPE_SORT); }
bool is_enum_sort(sort* s);
bool is_recursive(sort * ty);
+ bool is_recursive_array(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); }
bool is_recognizer0(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_RECOGNISER); }
diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp
index a817a5e2b..809cbe1f9 100644
--- a/src/ast/euf/euf_egraph.cpp
+++ b/src/ast/euf/euf_egraph.cpp
@@ -689,7 +689,7 @@ namespace euf {
if (ra->interpreted() && rb->interpreted()) {
explain_eq(justifications, a, ra);
explain_eq(justifications, b, rb);
- return UINT_MAX;
+ return sat::null_bool_var;
}
expr_ref eq(m.mk_eq(a->get_expr(), b->get_expr()), m);
m_tmp_eq->m_args[0] = a;
diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h
index fd9ef3d92..d2b4cf02a 100644
--- a/src/ast/euf/euf_enode.h
+++ b/src/ast/euf/euf_enode.h
@@ -19,6 +19,7 @@ Author:
#include "util/id_var_list.h"
#include "util/lbool.h"
#include "util/approx_set.h"
+#include "util/sat_literal.h"
#include "ast/ast.h"
#include "ast/euf/euf_justification.h"
@@ -41,28 +42,28 @@ namespace euf {
const theory_id null_theory_id = -1;
class enode {
- expr* m_expr{ nullptr };
- bool m_mark1{ false };
- bool m_mark2{ false };
- bool m_commutative{ false };
- bool m_update_children{ false };
- bool m_interpreted{ false };
- bool m_merge_enabled{ true };
- bool m_is_equality{ false }; // Does the expression represent an equality
- lbool m_value; // Assignment by SAT solver for Boolean node
- unsigned m_bool_var { UINT_MAX }; // SAT solver variable associated with Boolean node
- unsigned m_class_size{ 1 }; // Size of the equivalence class if the enode is the root.
- unsigned m_table_id{ UINT_MAX };
- unsigned m_generation { 0 }; // Tracks how many quantifier instantiation rounds were needed to generate this enode.
+ expr* m_expr = nullptr;
+ bool m_mark1 = false;
+ bool m_mark2 = false;
+ bool m_commutative = false;
+ bool m_update_children = false;
+ bool m_interpreted = false;
+ bool m_merge_enabled = true;
+ bool m_is_equality = false; // Does the expression represent an equality
+ lbool m_value = l_undef; // Assignment by SAT solver for Boolean node
+ sat::bool_var m_bool_var = sat::null_bool_var; // SAT solver variable associated with Boolean node
+ unsigned m_class_size = 1; // Size of the equivalence class if the enode is the root.
+ unsigned m_table_id = UINT_MAX;
+ unsigned m_generation = 0; // Tracks how many quantifier instantiation rounds were needed to generate this enode.
enode_vector m_parents;
- enode* m_next { nullptr };
- enode* m_root { nullptr };
- enode* m_target { nullptr };
- enode* m_cg { nullptr };
+ enode* m_next = nullptr;
+ enode* m_root = nullptr;
+ enode* m_target = nullptr;
+ enode* m_cg = nullptr;
th_var_list m_th_vars;
justification m_justification;
- unsigned m_num_args{ 0 };
- signed char m_lbl_hash { -1 }; // It is different from -1, if enode is used in a pattern
+ 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;
approx_set m_plbls;
enode* m_args[0];
@@ -135,7 +136,7 @@ namespace euf {
void set_merge_enabled(bool m) { m_merge_enabled = m; }
void set_value(lbool v) { m_value = v; }
void set_is_equality() { m_is_equality = true; }
- void set_bool_var(unsigned v) { m_bool_var = v; }
+ void set_bool_var(sat::bool_var v) { m_bool_var = v; }
public:
~enode() {
@@ -155,7 +156,8 @@ namespace euf {
bool interpreted() const { return m_interpreted; }
bool is_equality() const { return m_is_equality; }
lbool value() const { return m_value; }
- unsigned bool_var() const { return m_bool_var; }
+ bool value_conflict() const { return value() != l_undef && get_root()->value() != l_undef && value() != get_root()->value(); }
+ sat::bool_var bool_var() const { return m_bool_var; }
bool is_cgr() const { return this == m_cg; }
enode* get_cg() const { return m_cg; }
bool commutative() const { return m_commutative; }
diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp
index 390d6f63b..e0e2de1f7 100644
--- a/src/ast/normal_forms/pull_quant.cpp
+++ b/src/ast/normal_forms/pull_quant.cpp
@@ -276,7 +276,7 @@ struct pull_quant::imp {
if (is_exists(old_q)) {
result = m.mk_not(new_body);
- result = m.mk_not(m.update_quantifier(old_q, exists_k, result));
+ result = m.mk_not(m.update_quantifier(old_q, forall_k, result));
if (m.proofs_enabled())
m.mk_rewrite(old_q, result);
return true;
diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp
index fe9f84598..3411f8cec 100644
--- a/src/ast/recfun_decl_plugin.cpp
+++ b/src/ast/recfun_decl_plugin.cpp
@@ -54,7 +54,9 @@ namespace recfun {
unsigned arity, sort* const * domain, sort* range, bool is_generated)
: m(m), m_name(s),
m_domain(m, arity, domain),
- m_range(range, m), m_vars(m), m_cases(),
+ m_range(range, m),
+ m_vars(m),
+ m_cases(),
m_decl(m),
m_rhs(m),
m_fid(fid)
@@ -413,6 +415,16 @@ namespace recfun {
m_defs.insert(d->get_decl(), d);
return promise_def(&u(), d);
}
+
+ void plugin::erase_def(func_decl* f) {
+ def* d = nullptr;
+ if (m_defs.find(f, d)) {
+ for (case_def & c : d->get_cases())
+ m_case_defs.erase(c.get_decl());
+ m_defs.erase(f);
+ dealloc(d);
+ }
+ }
void plugin::set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) {
u().set_definition(r, d, n_vars, vars, rhs);
diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h
index 5a2ec9c71..22f2e76fe 100644
--- a/src/ast/recfun_decl_plugin.h
+++ b/src/ast/recfun_decl_plugin.h
@@ -186,6 +186,8 @@ namespace recfun {
def* mk_def(replace& subst, symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs);
+ void erase_def(func_decl* f);
+
bool has_def(func_decl* f) const { return m_defs.contains(f); }
bool has_defs() const;
def const& get_def(func_decl* f) const { return *(m_defs[f]); }
diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp
index 52ca18350..857ae0755 100644
--- a/src/ast/rewriter/arith_rewriter.cpp
+++ b/src/ast/rewriter/arith_rewriter.cpp
@@ -184,6 +184,8 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref &
kind = inv(kind);
r = true;
}
+ if (a.is_zero())
+ return false;
if (!a.is_one())
r = true;
if (!r)
diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h
index 7f796098f..fb997c35b 100644
--- a/src/ast/rewriter/ast_counter.h
+++ b/src/ast/rewriter/ast_counter.h
@@ -35,8 +35,6 @@ protected:
public:
typedef map_impl::iterator iterator;
- counter() {}
-
void reset() { m_data.reset(); }
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
@@ -74,7 +72,6 @@ protected:
unsigned_vector m_scopes;
unsigned get_max_var(bool & has_var);
public:
- var_counter() {}
void count_vars(const app * t, int coef = 1);
unsigned get_max_var(expr* e);
unsigned get_next_var(expr* e);
@@ -86,8 +83,6 @@ class ast_counter {
public:
typedef map_impl::iterator iterator;
- ast_counter() {}
-
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster.h b/src/ast/rewriter/bit_blaster/bit_blaster.h
index 8f2e7e50f..ca034337f 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster.h
+++ b/src/ast/rewriter/bit_blaster/bit_blaster.h
@@ -59,6 +59,7 @@ class bit_blaster : public bit_blaster_tpl {
public:
bit_blaster(ast_manager & m, bit_blaster_params const & params);
bit_blaster_params const & get_params() const { return this->m_params; }
+ void set_flat(bool f) { m_rw.set_flat(f); }
};
diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp
index c200ccc49..64427aecd 100644
--- a/src/ast/rewriter/quant_hoist.cpp
+++ b/src/ast/rewriter/quant_hoist.cpp
@@ -214,12 +214,10 @@ private:
pull_quantifier(a->get_arg(i), qt, vars, tmp, use_fresh, rewrite_ok);
args.push_back(tmp);
}
- if (rewrite_ok) {
- m_rewriter.mk_and(args.size(), args.data(), result);
- }
- else {
+ if (rewrite_ok)
+ m_rewriter.mk_and(args.size(), args.data(), result);
+ else
result = m.mk_and (args.size (), args.data ());
- }
}
else if (m.is_or(fml)) {
num_args = to_app(fml)->get_num_args();
@@ -227,12 +225,10 @@ private:
pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp, use_fresh, rewrite_ok);
args.push_back(tmp);
}
- if (rewrite_ok) {
- m_rewriter.mk_or(args.size(), args.data(), result);
- }
- else {
+ if (rewrite_ok)
+ m_rewriter.mk_or(args.size(), args.data(), result);
+ else
result = m.mk_or (args.size (), args.data ());
- }
}
else if (m.is_not(fml)) {
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp, use_fresh, rewrite_ok);
diff --git a/src/ast/rewriter/recfun_rewriter.h b/src/ast/rewriter/recfun_rewriter.h
index a08a75783..f1c2ae442 100644
--- a/src/ast/rewriter/recfun_rewriter.h
+++ b/src/ast/rewriter/recfun_rewriter.h
@@ -26,7 +26,6 @@ class recfun_rewriter {
recfun::util m_rec;
public:
recfun_rewriter(ast_manager& m): m(m), m_rec(m) {}
- ~recfun_rewriter() {}
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp
index 0ca46f082..9049ad971 100644
--- a/src/ast/rewriter/seq_rewriter.cpp
+++ b/src/ast/rewriter/seq_rewriter.cpp
@@ -432,6 +432,7 @@ br_status seq_rewriter::mk_bool_app_helper(bool is_and, unsigned n, expr* const*
obj_map in_re, not_in_re;
bool found_pair = false;
+ ptr_buffer new_args;
for (unsigned i = 0; i < n; ++i) {
expr* args_i = args[i];
expr* x = nullptr, *y = nullptr, *z = nullptr;
@@ -455,13 +456,15 @@ br_status seq_rewriter::mk_bool_app_helper(bool is_and, unsigned n, expr* const*
found_pair |= in_re.contains(x);
}
}
+ else
+ new_args.push_back(args_i);
}
if (!found_pair) {
return BR_FAILED;
}
- ptr_buffer new_args;
+
for (auto const & kv : in_re) {
expr* x = kv.m_key;
expr* y = kv.m_value;
@@ -482,12 +485,6 @@ br_status seq_rewriter::mk_bool_app_helper(bool is_and, unsigned n, expr* const*
new_args.push_back(re().mk_in_re(x, re().mk_complement(y)));
}
}
- for (unsigned i = 0; i < n; ++i) {
- expr* arg = args[i], * x;
- if (!str().is_in_re(arg) && !(m().is_not(arg, x) && str().is_in_re(x))) {
- new_args.push_back(arg);
- }
- }
result = is_and ? m().mk_and(new_args) : m().mk_or(new_args);
return BR_REWRITE_FULL;
@@ -2500,7 +2497,7 @@ expr_ref seq_rewriter::is_nullable(expr* r) {
m_op_cache.insert(_OP_RE_IS_NULLABLE, r, nullptr, result);
}
STRACE("seq_verbose", tout << "is_nullable result: "
- << mk_pp(result, m()) << std::endl;);
+ << result << std::endl;);
return result;
}
diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp
index a61cfdc4e..ec33bd265 100644
--- a/src/ast/rewriter/var_subst.cpp
+++ b/src/ast/rewriter/var_subst.cpp
@@ -17,6 +17,7 @@ Notes:
--*/
#include "ast/rewriter/var_subst.h"
+#include "ast/rewriter/expr_safe_replace.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
#include "ast/ast_smt2_pp.h"
@@ -24,8 +25,9 @@ Notes:
#include "ast/for_each_expr.h"
expr_ref var_subst::operator()(expr * n, unsigned num_args, expr * const * args) {
- expr_ref result(m_reducer.m());
- if (is_ground(n)) {
+ ast_manager& m = m_reducer.m();
+ expr_ref result(m);
+ if (is_ground(n) || num_args == 0) {
result = n;
//application does not have free variables or nested quantifiers.
//There is no need to print the bindings here?
@@ -40,6 +42,16 @@ expr_ref var_subst::operator()(expr * n, unsigned num_args, expr * const * args)
return result;
}
+ if (has_quantifiers(n)) {
+ expr_safe_replace rep(m);
+ for (unsigned k = 0; k < num_args; ++k) {
+ expr* arg = args[k];
+ if (arg)
+ rep.insert(m.mk_var(m_std_order ? num_args - k - 1 : k, arg->get_sort()), arg);
+ }
+ rep(n, result);
+ return result;
+ }
SASSERT(is_well_sorted(result.m(), n));
m_reducer.reset();
if (m_std_order)
@@ -47,10 +59,10 @@ expr_ref var_subst::operator()(expr * n, unsigned num_args, expr * const * args)
else
m_reducer.set_bindings(num_args, args);
m_reducer(n, result);
- SASSERT(is_well_sorted(m_reducer.m(), result));
+ SASSERT(is_well_sorted(m, result));
TRACE("var_subst_bug",
- tout << "m_std_order: " << m_std_order << "\n" << mk_ismt2_pp(n, m_reducer.m()) << "\nusing\n";
- for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m_reducer.m()) << "\n";
+ tout << "m_std_order: " << m_std_order << "\n" << mk_ismt2_pp(n, m) << "\nusing\n";
+ for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m) << "\n";
tout << "\n------>\n";
tout << result << "\n";);
return result;
diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp
index 5213bbba9..7c76b3f64 100644
--- a/src/ast/seq_decl_plugin.cpp
+++ b/src/ast/seq_decl_plugin.cpp
@@ -1269,7 +1269,7 @@ seq_util::rex::info seq_util::rex::mk_info_rec(app* e) const {
case OP_RE_OPTION:
i1 = get_info_rec(e->get_arg(0));
return i1.opt();
- case OP_RE_RANGE:
+ case OP_RE_RANGE:
case OP_RE_FULL_CHAR_SET:
case OP_RE_OF_PRED:
//TBD: check if the character predicate contains uninterpreted symbols or is nonground or is unsat
diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h
index 9adb4df32..01f88112b 100644
--- a/src/ast/seq_decl_plugin.h
+++ b/src/ast/seq_decl_plugin.h
@@ -160,7 +160,6 @@ class seq_decl_plugin : public decl_plugin {
public:
seq_decl_plugin();
- ~seq_decl_plugin() override {}
void finalize() override;
bool unicode() const { return get_char_plugin().unicode(); }
@@ -575,8 +574,6 @@ public:
re(*this) {
}
- ~seq_util() {}
-
family_id get_family_id() const { return m_fid; }
};
diff --git a/src/ast/shared_occs.h b/src/ast/shared_occs.h
index 468ce1436..59ff99569 100644
--- a/src/ast/shared_occs.h
+++ b/src/ast/shared_occs.h
@@ -24,8 +24,6 @@ Revision History:
class shared_occs_mark {
ptr_buffer m_to_unmark;
public:
- shared_occs_mark() {}
-
~shared_occs_mark() {
reset();
}
diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp
index 227082e6f..5e43a0273 100644
--- a/src/ast/static_features.cpp
+++ b/src/ast/static_features.cpp
@@ -104,7 +104,7 @@ void static_features::reset() {
m_num_aliens_per_family .reset();
m_num_theories = 0;
m_theories .reset();
- m_max_stack_depth = 100;
+ m_max_stack_depth = 30;
flush_cache();
}
diff --git a/src/ast/substitution/matcher.h b/src/ast/substitution/matcher.h
index 2c398956f..6ef02f284 100644
--- a/src/ast/substitution/matcher.h
+++ b/src/ast/substitution/matcher.h
@@ -36,8 +36,6 @@ class matcher {
void reset();
public:
- matcher() {}
-
/**
\brief Return true if e2 is an instance of e1.
In case of success (result is true), it will store the substitution that makes e1 equals to e2 into s.
diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp
index fd8eeb3f1..2ec910595 100644
--- a/src/cmd_context/cmd_context.cpp
+++ b/src/cmd_context/cmd_context.cpp
@@ -352,7 +352,21 @@ void cmd_context::insert_macro(symbol const& s, unsigned arity, sort*const* doma
else {
VERIFY(decls.insert(m(), arity, domain, t));
}
- model_add(s, arity, domain, t);
+
+ recfun::decl::plugin& p = get_recfun_plugin();
+ recfun_replace replace(m());
+ var_ref_vector vars(m()), rvars(m());
+ for (unsigned i = 0; i < arity; ++i) {
+ vars.push_back(m().mk_var(i, domain[i]));
+ rvars.push_back(m().mk_var(i, domain[arity - i - 1]));
+ }
+ recfun::promise_def d = p.ensure_def(s, arity, domain, t->get_sort());
+
+ // recursive functions have opposite calling convention from macros!
+ var_subst sub(m(), true);
+ expr_ref tt = sub(t, rvars);
+ p.set_definition(replace, d, vars.size(), vars.data(), tt);
+ register_fun(s, d.get_def()->get_decl());
}
void cmd_context::erase_macro(symbol const& s) {
@@ -940,17 +954,23 @@ void cmd_context::insert(symbol const & s, object_ref * r) {
}
void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
+
if (!mc0()) m_mcs.set(m_mcs.size()-1, alloc(generic_model_converter, m(), "cmd_context"));
if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(mc0());
+
func_decl_ref fn(m().mk_func_decl(s, arity, domain, t->get_sort()), m());
- func_decls & fs = m_func_decls.insert_if_not_there(s, func_decls());
- fs.insert(m(), fn);
- VERIFY(fn->get_range() == t->get_sort());
mc0()->add(fn, t);
- if (!m_global_decls)
- m_func_decls_stack.push_back(sf_pair(s, fn));
+ VERIFY(fn->get_range() == t->get_sort());
+ register_fun(s, fn);
}
+void cmd_context::register_fun(symbol const& s, func_decl* fn) {
+ func_decls & fs = m_func_decls.insert_if_not_there(s, func_decls());
+ fs.insert(m(), fn);
+ if (!m_global_decls)
+ m_func_decls_stack.push_back(sf_pair(s, fn));
+
+}
void cmd_context::model_del(func_decl* f) {
if (!mc0()) m_mcs.set(m_mcs.size() - 1, alloc(generic_model_converter, m(), "cmd_context"));
@@ -1230,6 +1250,8 @@ void cmd_context::erase_func_decl_core(symbol const & s, func_decl * f) {
SASSERT(m_func_decl2alias.contains(f));
m_func_decl2alias.erase(f);
}
+
+ get_recfun_plugin().erase_def(f);
fs.erase(m(), f);
if (fs.empty())
m_func_decls.erase(s);
@@ -1751,7 +1773,9 @@ void cmd_context::add_declared_functions(model& mdl) {
mdl.register_decl(f, fi);
}
}
+ mdl.add_rec_funs();
}
+
}
void cmd_context::display_sat_result(lbool r) {
diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h
index 61595e266..4b669e559 100644
--- a/src/cmd_context/cmd_context.h
+++ b/src/cmd_context/cmd_context.h
@@ -94,9 +94,8 @@ public:
\brief Generic wrapper.
*/
class object_ref {
- unsigned m_ref_count;
+ unsigned m_ref_count = 0;
public:
- object_ref():m_ref_count(0) {}
virtual ~object_ref() {}
virtual void finalize(cmd_context & ctx) = 0;
void inc_ref(cmd_context & ctx) {
@@ -406,6 +405,7 @@ public:
void insert_aux_pdecl(pdecl * p);
void model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t);
void model_del(func_decl* f);
+ void register_fun(symbol const& s, func_decl* f);
void insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e);
func_decl * find_func_decl(symbol const & s) const;
func_decl * find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
diff --git a/src/cmd_context/cmd_context_to_goal.cpp b/src/cmd_context/cmd_context_to_goal.cpp
index de19805f2..0b1644171 100644
--- a/src/cmd_context/cmd_context_to_goal.cpp
+++ b/src/cmd_context/cmd_context_to_goal.cpp
@@ -25,13 +25,14 @@ Notes:
void assert_exprs_from(cmd_context const & ctx, goal & t) {
if (ctx.produce_proofs() && ctx.produce_unsat_cores())
throw cmd_exception("Frontend does not support simultaneous generation of proofs and unsat cores");
+ if (ctx.produce_unsat_cores() && ctx.assertions().size() != ctx.assertion_names().size())
+ throw cmd_exception("Unsat core tracking must be set before assertions are added");
ast_manager & m = t.m();
bool proofs_enabled = t.proofs_enabled();
if (ctx.produce_unsat_cores()) {
ptr_vector::const_iterator it = ctx.assertions().begin();
ptr_vector::const_iterator end = ctx.assertions().end();
ptr_vector::const_iterator it2 = ctx.assertion_names().begin();
- SASSERT(ctx.assertions().size() == ctx.assertion_names().size());
for (; it != end; ++it, ++it2) {
t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : nullptr, m.mk_leaf(*it2));
}
diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp
index bf9da152f..af030e139 100644
--- a/src/cmd_context/tactic_cmds.cpp
+++ b/src/cmd_context/tactic_cmds.cpp
@@ -166,9 +166,9 @@ public:
}
};
-class check_sat_using_tactict_cmd : public exec_given_tactic_cmd {
+class check_sat_using_tactic_cmd : public exec_given_tactic_cmd {
public:
- check_sat_using_tactict_cmd():
+ check_sat_using_tactic_cmd():
exec_given_tactic_cmd("check-sat-using") {
}
@@ -397,7 +397,7 @@ void install_core_tactic_cmds(cmd_context & ctx) {
ctx.insert(alloc(declare_tactic_cmd));
ctx.insert(alloc(get_user_tactics_cmd));
ctx.insert(alloc(help_tactic_cmd));
- ctx.insert(alloc(check_sat_using_tactict_cmd));
+ ctx.insert(alloc(check_sat_using_tactic_cmd));
ctx.insert(alloc(apply_tactic_cmd));
install_tactics(ctx);
}
diff --git a/src/math/dd/pdd_eval.h b/src/math/dd/pdd_eval.h
index 3a5e85cf4..f7682927f 100644
--- a/src/math/dd/pdd_eval.h
+++ b/src/math/dd/pdd_eval.h
@@ -26,9 +26,6 @@ class pdd_eval {
std::function m_var2val;
public:
-
- pdd_eval() {}
-
std::function& var2val() { return m_var2val; } // setter
const std::function& var2val() const { return m_var2val; } // getter
diff --git a/src/math/grobner/pdd_simplifier.h b/src/math/grobner/pdd_simplifier.h
index c3fdbe036..065350cb1 100644
--- a/src/math/grobner/pdd_simplifier.h
+++ b/src/math/grobner/pdd_simplifier.h
@@ -27,7 +27,6 @@ class simplifier {
public:
simplifier(solver& s): s(s) {}
- ~simplifier() {}
void operator()();
diff --git a/src/math/lp/gomory.h b/src/math/lp/gomory.h
index 58f1288d6..68e42feb9 100644
--- a/src/math/lp/gomory.h
+++ b/src/math/lp/gomory.h
@@ -32,7 +32,6 @@ namespace lp {
lia_move cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row);
public:
gomory(int_solver& lia);
- ~gomory() {}
lia_move operator()();
};
}
diff --git a/src/math/lp/int_branch.h b/src/math/lp/int_branch.h
index a7d72383a..9601cb65e 100644
--- a/src/math/lp/int_branch.h
+++ b/src/math/lp/int_branch.h
@@ -32,7 +32,6 @@ namespace lp {
public:
int_branch(int_solver& lia);
- ~int_branch() {}
lia_move operator()();
};
}
diff --git a/src/math/lp/int_cube.h b/src/math/lp/int_cube.h
index 18af0cbc1..4addc096b 100644
--- a/src/math/lp/int_cube.h
+++ b/src/math/lp/int_cube.h
@@ -35,7 +35,6 @@ namespace lp {
impq get_cube_delta_for_term(const lar_term& t) const;
public:
int_cube(int_solver& lia);
- ~int_cube() {}
lia_move operator()();
};
}
diff --git a/src/math/lp/int_gcd_test.cpp b/src/math/lp/int_gcd_test.cpp
index 6e05d69e7..4801cc436 100644
--- a/src/math/lp/int_gcd_test.cpp
+++ b/src/math/lp/int_gcd_test.cpp
@@ -42,6 +42,8 @@ Accumulative:
- Otherwise accumulate x = (c1 * lcm(b1,b2) / b2) + (c2 * lcm(b1,b2) / b1) mod lcm(b,b2)
and accumulate the rows from R1, R2
+
+
--*/
#include "math/lp/int_solver.h"
@@ -53,10 +55,7 @@ namespace lp {
int_gcd_test::int_gcd_test(int_solver& lia): lia(lia), lra(lia.lra), m_next_gcd(0), m_delay(0) {}
bool int_gcd_test::should_apply() {
-
- if (!lia.settings().int_run_gcd_test())
- return false;
- return true;
+ return lia.settings().int_run_gcd_test();
}
lia_move int_gcd_test::operator()() {
@@ -76,18 +75,36 @@ namespace lp {
}
bool int_gcd_test::gcd_test() {
+ reset_test();
const auto & A = lra.A_r(); // getting the matrix
- for (unsigned i = 0; i < A.row_count(); i++)
+ for (unsigned i = 0; i < A.row_count(); i++) {
+ unsigned basic_var = lra.r_basis()[i];
+ if (!lia.column_is_int(basic_var))
+ continue;
+ if (lia.get_value(basic_var).is_int())
+ continue;
if (!gcd_test_for_row(A, i))
return false;
+ mark_visited(i);
+ }
+ for (unsigned i = m_inserted_vars.size(); i-- > 0; ) {
+ unsigned j = m_inserted_vars[i];
+ for (const auto & c : lra.get_column(j)) {
+ unsigned r = c.var();
+ if (is_visited(r))
+ continue;
+ mark_visited(r);
+ if (!gcd_test_for_row(A, r))
+ return false;
+ }
+ }
return true;
}
static mpq get_denominators_lcm(const row_strip & row) {
mpq r(1);
- for (auto & c : row) {
+ for (auto & c : row)
r = lcm(r, denominator(c.coeff()));
- }
return r;
}
@@ -95,44 +112,50 @@ namespace lp {
auto const& row = A.m_rows[i];
unsigned basic_var = lra.r_basis()[i];
- if (!lia.column_is_int(basic_var) || lia.get_value(basic_var).is_int())
+ if (!lia.column_is_int(basic_var))
return true;
- mpq lcm_den = get_denominators_lcm(row);
- mpq consts(0);
+ m_lcm_den = get_denominators_lcm(row);
+ m_consts = 0;
mpq gcds(0);
- mpq least_coeff(0);
- bool least_coeff_is_bounded = false;
- unsigned j;
+ m_least_coeff = 0;
+ bool least_coeff_is_bounded = false;
+ bool least_coeff_is_unique = false;
+ unsigned least_coeff_index = 0;
for (auto &c : A.m_rows[i]) {
- j = c.var();
+ unsigned j = c.var();
const mpq& a = c.coeff();
if (lra.column_is_fixed(j)) {
- mpq aux = lcm_den * a;
- consts += aux * lra.column_lower_bound(j).x;
+ mpq aux = m_lcm_den * a;
+ m_consts += aux * lra.column_lower_bound(j).x;
}
else if (lra.column_is_real(j)) {
return true;
}
else if (gcds.is_zero()) {
- gcds = abs(lcm_den * a);
- least_coeff = gcds;
+ gcds = abs(m_lcm_den * a);
+ m_least_coeff = gcds;
least_coeff_is_bounded = lra.column_is_bounded(j);
+ least_coeff_is_unique = true;
+ least_coeff_index = j;
}
else {
- mpq aux = abs(lcm_den * a);
+ mpq aux = abs(m_lcm_den * a);
gcds = gcd(gcds, aux);
- if (aux < least_coeff) {
- least_coeff = aux;
+ if (aux < m_least_coeff) {
+ m_least_coeff = aux;
least_coeff_is_bounded = lra.column_is_bounded(j);
+ least_coeff_is_unique = true;
+ least_coeff_index = j;
}
- else if (least_coeff_is_bounded && aux == least_coeff) {
- least_coeff_is_bounded = lra.column_is_bounded(j);
+ else if (aux == m_least_coeff) {
+ least_coeff_is_bounded &= lra.column_is_bounded(j);
+ least_coeff_is_unique = false;
}
}
SASSERT(gcds.is_int());
- SASSERT(least_coeff.is_int());
+ SASSERT(m_least_coeff.is_int());
TRACE("gcd_test_bug", tout << "coeff: " << a << ", gcds: " << gcds
- << " least_coeff: " << least_coeff << " consts: " << consts << "\n";);
+ << " least_coeff: " << m_least_coeff << " consts: " << m_consts << "\n";);
}
@@ -143,31 +166,29 @@ namespace lp {
return true;
}
- if (!(consts / gcds).is_int()) {
+ if (!(m_consts / gcds).is_int()) {
TRACE("gcd_test", tout << "row failed the GCD test:\n"; lia.display_row_info(tout, i););
fill_explanation_from_fixed_columns(A.m_rows[i]);
return false;
}
-
- if (least_coeff.is_one() && !least_coeff_is_bounded) {
- SASSERT(gcds.is_one());
+
+ if (least_coeff_is_bounded &&
+ !m_least_coeff.is_one() &&
+ !lia.get_value(basic_var).is_int() &&
+ !ext_gcd_test(A.m_rows[i]))
+ return false;
+
+ if (!least_coeff_is_unique)
return true;
- }
-
- if (least_coeff_is_bounded) {
- return ext_gcd_test(A.m_rows[i], least_coeff, lcm_den, consts);
- }
- return true;
+
+ return accumulate_parity(row, least_coeff_index);
}
- bool int_gcd_test::ext_gcd_test(const row_strip & row,
- mpq const & least_coeff,
- mpq const & lcm_den,
- mpq const & consts) {
+ bool int_gcd_test::ext_gcd_test(const row_strip & row) {
TRACE("ext_gcd_test", tout << "row = "; lra.print_row(row, tout););
mpq gcds(0);
- mpq l(consts);
- mpq u(consts);
+ mpq l(m_consts);
+ mpq u(m_consts);
mpq a;
unsigned j;
@@ -178,10 +199,10 @@ namespace lp {
if (lra.column_is_fixed(j))
continue;
SASSERT(!lra.column_is_real(j));
- mpq ncoeff = lcm_den * a;
+ mpq ncoeff = m_lcm_den * a;
SASSERT(ncoeff.is_int());
mpq abs_ncoeff = abs(ncoeff);
- if (abs_ncoeff == least_coeff) {
+ if (abs_ncoeff == m_least_coeff) {
SASSERT(lra.column_is_bounded(j));
if (ncoeff.is_pos()) {
// l += ncoeff * lra.column_lower_bound(j).x;
@@ -235,4 +256,72 @@ namespace lp {
lia.m_ex->push_back(uc);
}
+ bool int_gcd_test::accumulate_parity(const row_strip & row, unsigned least_idx) {
+
+ // remove this line to enable new functionality.
+ // return true;
+
+ mpq modulus(0);
+ bool least_sign = false;
+ for (const auto & c : row) {
+ unsigned j = c.var();
+ const mpq& a = c.coeff();
+ if (j == least_idx)
+ least_sign = a.is_neg();
+ else if (!lra.column_is_fixed(j)) {
+ mpq aux = abs(m_lcm_den * a);
+ if (gcd(m_least_coeff, aux) != m_least_coeff)
+ return true;
+ modulus = modulus == 0 ? aux : gcd(modulus, aux);
+ if (modulus.is_one())
+ return true;
+ }
+ }
+ modulus /= m_least_coeff;
+ if (modulus == 0)
+ return true;
+ SASSERT(modulus.is_int());
+ mpq offset = m_consts / m_least_coeff;
+ if (!offset.is_int())
+ return true;
+ offset = mod(offset, modulus);
+ if (!least_sign && offset != 0)
+ offset = modulus - offset;
+ TRACE("gcd_test", tout << least_idx << " modulus: " << modulus << " consts: " << m_consts << " sign " << least_sign << " offset: " << offset << "\n";);
+
+ SASSERT(0 <= offset && offset < modulus);
+ return insert_parity(least_idx, row, offset, modulus);
+ }
+
+ void int_gcd_test::reset_test() {
+ for (auto j : m_inserted_vars)
+ m_parities[j].pop_back();
+ m_inserted_vars.reset();
+ m_visited_ts++;
+ if (m_visited_ts == 0) {
+ m_visited.reset();
+ m_visited_ts++;
+ }
+ }
+
+ bool int_gcd_test::insert_parity(unsigned j, row_strip const& r, mpq const& offset, mpq const& modulo) {
+ m_parities.reserve(j + 1);
+
+ // incomplete parity check.
+ for (auto const& p : m_parities[j]) {
+ if (p.m_modulo != modulo)
+ continue;
+ if (p.m_offset == offset)
+ return true;
+ else {
+ fill_explanation_from_fixed_columns(r);
+ fill_explanation_from_fixed_columns(*p.m_row);
+ return false;
+ }
+ }
+ m_inserted_vars.push_back(j);
+ m_parities[j].push_back(parity(offset, modulo, r));
+ return true;
+ }
+
}
diff --git a/src/math/lp/int_gcd_test.h b/src/math/lp/int_gcd_test.h
index 0734dc8af..28ac2f7b3 100644
--- a/src/math/lp/int_gcd_test.h
+++ b/src/math/lp/int_gcd_test.h
@@ -32,22 +32,43 @@ namespace lp {
class int_solver;
class lar_solver;
class int_gcd_test {
+
+ struct parity {
+ mpq m_offset;
+ mpq m_modulo;
+ const row_strip* m_row = nullptr;
+ parity(mpq const& p, mpq const& m, row_strip const& r):
+ m_offset(p),
+ m_modulo(m),
+ m_row(&r)
+ {}
+ };
class int_solver& lia;
class lar_solver& lra;
- unsigned m_next_gcd;
- unsigned m_delay;
+ unsigned m_next_gcd = 0;
+ unsigned m_delay = 0;
+ mpq m_consts;
+ mpq m_least_coeff;
+ mpq m_lcm_den;
+ unsigned_vector m_inserted_vars;
+ vector> m_parities;
+ unsigned_vector m_visited;
+ unsigned m_visited_ts = 0;
+
+ bool is_visited(unsigned i) { return m_visited.get(i, 0) == m_visited_ts; }
+ void mark_visited(unsigned i) { m_visited.setx(i, m_visited_ts, 0); }
+
+ void reset_test();
+ bool insert_parity(unsigned j, row_strip const& r, mpq const& parity, mpq const& modulo);
bool gcd_test();
bool gcd_test_for_row(const static_matrix> & A, unsigned i);
- bool ext_gcd_test(const row_strip & row,
- mpq const & least_coeff,
- mpq const & lcm_den,
- mpq const & consts);
+ bool ext_gcd_test(const row_strip & row);
void fill_explanation_from_fixed_columns(const row_strip & row);
void add_to_explanation_from_fixed_or_boxed_column(unsigned j);
+ bool accumulate_parity(const row_strip & row, unsigned least_coeff_index);
public:
int_gcd_test(int_solver& lia);
- ~int_gcd_test() {}
lia_move operator()();
bool should_apply();
};
diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h
index 054c94cc0..115e1a344 100644
--- a/src/math/lp/lp_primal_core_solver_tableau_def.h
+++ b/src/math/lp/lp_primal_core_solver_tableau_def.h
@@ -179,34 +179,33 @@ unsigned lp_primal_core_solver::solve_with_tableau() {
default:
break; // do nothing
}
+ if (this->m_settings.get_cancel_flag()
+ ||
+ this->iters_with_no_cost_growing() > this->m_settings.max_number_of_iterations_with_no_improvements
+ ||
+ this->total_iterations() > this->m_settings.max_total_number_of_iterations
+ ) {
+ this->set_status(lp_status::CANCELLED);
+ break; // from the loop
+ }
} while (this->get_status() != lp_status::FLOATING_POINT_ERROR
- &&
+ &&
this->get_status() != lp_status::UNBOUNDED
- &&
+ &&
this->get_status() != lp_status::OPTIMAL
- &&
+ &&
this->get_status() != lp_status::INFEASIBLE
- &&
- this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
- &&
- this->total_iterations() <= this->m_settings.max_total_number_of_iterations
- &&
- !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
- &&
- this->m_settings.get_cancel_flag() == false);
+ &&
+ !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
+ );
- if (this->m_settings.get_cancel_flag()) {
- this->set_status(lp_status::CANCELLED);
- }
-
- lp_assert(
- this->get_status() == lp_status::FLOATING_POINT_ERROR
- ||
- this->get_status() == lp_status::CANCELLED
- ||
- this->current_x_is_feasible() == false
- ||
- this->calc_current_x_is_feasible_include_non_basis());
+ lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR
+ ||
+ this->get_status() == lp_status::CANCELLED
+ ||
+ this->current_x_is_feasible() == false
+ ||
+ this->calc_current_x_is_feasible_include_non_basis());
return this->total_iterations();
}
diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h
index b850be15b..594e9b6f4 100644
--- a/src/math/lp/lp_settings.h
+++ b/src/math/lp/lp_settings.h
@@ -140,6 +140,7 @@ struct statistics {
st.update("arith-patches", m_patches);
st.update("arith-patches-success", m_patches_success);
st.update("arith-hnf-calls", m_hnf_cutter_calls);
+ st.update("arith-hnf-cuts", m_hnf_cuts);
st.update("arith-horner-calls", m_horner_calls);
st.update("arith-horner-conflicts", m_horner_conflicts);
st.update("arith-horner-cross-nested-forms", m_cross_nested_forms);
@@ -208,7 +209,7 @@ public:
double harris_feasibility_tolerance { 1e-7 }; // page 179 of Istvan Maros
double ignore_epsilon_of_harris { 10e-5 };
unsigned max_number_of_iterations_with_no_improvements { 2000000 };
- unsigned max_total_number_of_iterations { 2000000 };
+ unsigned max_total_number_of_iterations { 20000000 };
double time_limit; // the maximum time limit of the total run time in seconds
// dual section
double dual_feasibility_tolerance { 1e-7 }; // page 71 of the PhD thesis of Achim Koberstein
diff --git a/src/math/lp/nex.h b/src/math/lp/nex.h
index 26759cb33..083b935a4 100644
--- a/src/math/lp/nex.h
+++ b/src/math/lp/nex.h
@@ -54,7 +54,6 @@ public:
virtual unsigned size() const { return 1; }
virtual expr_type type() const = 0;
virtual std::ostream& print(std::ostream&) const = 0;
- nex() {}
bool is_elementary() const {
switch(type()) {
case expr_type::SUM:
diff --git a/src/math/simplex/bit_matrix.h b/src/math/simplex/bit_matrix.h
index 189472d6a..c827690ec 100644
--- a/src/math/simplex/bit_matrix.h
+++ b/src/math/simplex/bit_matrix.h
@@ -92,8 +92,6 @@ public:
bool operator!=(row_iterator const& other) const { return m_index != other.m_index; }
};
- bit_matrix() {}
- ~bit_matrix() {}
void reset(unsigned num_columns);
row_iterator begin() { return row_iterator(*this, true); }
diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp
index a52dabf9e..e785c33ed 100644
--- a/src/math/simplex/model_based_opt.cpp
+++ b/src/math/simplex/model_based_opt.cpp
@@ -166,7 +166,7 @@ namespace opt {
return true;
}
-#define PASSERT(_e_) if (!(_e_)) { TRACE("opt1", display(tout, r); display(tout);); SASSERT(_e_); }
+#define PASSERT(_e_) { CTRACE("qe", !(_e_), display(tout, r); display(tout);); SASSERT(_e_); }
bool model_based_opt::invariant(unsigned index, row const& r) {
vector const& vars = r.m_vars;
@@ -378,7 +378,8 @@ namespace opt {
}
else if ((value == lub_val && r.m_type == opt::t_lt) ||
(is_pos && value < lub_val) ||
- (!is_pos && value > lub_val)) {
+
+ (!is_pos && value > lub_val)) {
m_above.push_back(bound_row_index);
lub_val = value;
bound_row_index = row_id;
@@ -423,6 +424,13 @@ namespace opt {
}
return val;
}
+
+ rational model_based_opt::eval(vector const& coeffs) const {
+ rational val(0);
+ for (var const& v : coeffs)
+ val += v.m_coeff * eval(v.m_id);
+ return val;
+ }
rational model_based_opt::get_coefficient(unsigned row_id, unsigned var_id) const {
return m_rows[row_id].get_coefficient(var_id);
@@ -787,7 +795,7 @@ namespace opt {
}
std::ostream& model_based_opt::display(std::ostream& out, row const& r) {
- out << (r.m_alive?"+":"-") << " ";
+ out << (r.m_alive?"a":"d") << " ";
display(out, r.m_vars, r.m_coeff);
if (r.m_type == opt::t_mod) {
out << r.m_type << " " << r.m_mod << " = 0; value: " << r.m_value << "\n";
@@ -1002,8 +1010,7 @@ namespace opt {
result = solve_for(glb_index, x, true);
}
else {
- result = def();
- m_var2value[x] = rational::zero();
+ result = def() + m_var2value[x];
}
SASSERT(eval(result) == eval(x));
}
@@ -1123,9 +1130,8 @@ namespace opt {
}
TRACE("opt1", display(tout << "tableau after replace x by y := v" << y << "\n"););
def result = project(y, compute_def);
- if (compute_def) {
+ if (compute_def)
result = (result * D) + u;
- }
SASSERT(!compute_def || eval(result) == eval(x));
return result;
}
@@ -1187,13 +1193,15 @@ namespace opt {
SASSERT(a.is_pos());
if (ty == t_lt) {
SASSERT(compute_def);
- m_rows[row_id1].m_coeff += a;
+ m_rows[row_id1].m_coeff += a;
+ m_rows[row_id1].m_type = t_le;
+ m_rows[row_id1].m_value += a;
}
if (m_var2is_int[x] && !a.is_one()) {
row& r1 = m_rows[row_id1];
vector coeffs;
mk_coeffs_without(coeffs, r1.m_vars, x);
- rational c = r1.m_coeff;
+ rational c = mod(-eval(coeffs), a);
add_divides(coeffs, c, a);
}
unsigned_vector const& row_ids = m_var2row_ids[x];
@@ -1203,19 +1211,19 @@ namespace opt {
if (!visited.contains(row_id2)) {
visited.insert(row_id2);
b = get_coefficient(row_id2, x);
- if (!b.is_zero()) {
- row& dst = m_rows[row_id2];
- switch (dst.m_type) {
- case t_eq:
- case t_lt:
- case t_le:
- solve(row_id1, a, row_id2, x);
- break;
- case t_mod:
- // mod reduction already done.
- UNREACHABLE();
- break;
- }
+ if (b.is_zero())
+ continue;
+ row& dst = m_rows[row_id2];
+ switch (dst.m_type) {
+ case t_eq:
+ case t_lt:
+ case t_le:
+ solve(row_id1, a, row_id2, x);
+ break;
+ case t_mod:
+ // mod reduction already done.
+ UNREACHABLE();
+ break;
}
}
}
diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h
index 047f03cc4..bb6f8f91c 100644
--- a/src/math/simplex/model_based_opt.h
+++ b/src/math/simplex/model_based_opt.h
@@ -104,6 +104,8 @@ namespace opt {
rational eval(unsigned x) const;
rational eval(def const& d) const;
+
+ rational eval(vector const& coeffs) const;
void resolve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x);
diff --git a/src/math/subpaving/subpaving_types.h b/src/math/subpaving/subpaving_types.h
index 28150cc04..b914901a8 100644
--- a/src/math/subpaving/subpaving_types.h
+++ b/src/math/subpaving/subpaving_types.h
@@ -31,7 +31,7 @@ class exception {
class power : public std::pair {
public:
- power():std::pair() {}
+ power() = default;
power(var v, unsigned d):std::pair(v, d) {}
var x() const { return first; }
var get_var() const { return first; }
diff --git a/src/model/array_factory.cpp b/src/model/array_factory.cpp
index b68d708a1..6fab80661 100644
--- a/src/model/array_factory.cpp
+++ b/src/model/array_factory.cpp
@@ -132,13 +132,19 @@ expr * array_factory::get_fresh_value(sort * s) {
return get_some_value(s);
}
sort * range = get_array_range(s);
- expr * range_val = m_model.get_fresh_value(range);
- if (range_val != nullptr) {
- // easy case
- func_interp * fi;
- expr * val = mk_array_interp(s, fi);
- fi->set_else(range_val);
- return val;
+ expr* range_val = nullptr;
+
+ if (!m_ranges.contains(range)) {
+ ptr_vector::scoped_stack _s(m_ranges);
+ m_ranges.push_back(range);
+ range_val = m_model.get_fresh_value(range);
+ if (range_val != nullptr) {
+ // easy case
+ func_interp* fi;
+ expr* val = mk_array_interp(s, fi);
+ fi->set_else(range_val);
+ return val;
+ }
}
TRACE("array_factory_bug", tout << "array fresh value: using fresh index, range: " << mk_pp(range, m_manager) << "\n";);
diff --git a/src/model/array_factory.h b/src/model/array_factory.h
index a213850f2..c4bfc05df 100644
--- a/src/model/array_factory.h
+++ b/src/model/array_factory.h
@@ -28,6 +28,7 @@ class array_factory : public struct_factory {
expr * mk_array_interp(sort * s, func_interp * & fi);
void get_some_args_for(sort * s, ptr_buffer & args);
bool mk_two_diff_values_for(sort * s);
+ ptr_vector m_ranges;
public:
array_factory(ast_manager & m, model_core & md);
diff --git a/src/model/datatype_factory.cpp b/src/model/datatype_factory.cpp
index e59ae14f2..b5e769d2e 100644
--- a/src/model/datatype_factory.cpp
+++ b/src/model/datatype_factory.cpp
@@ -27,6 +27,8 @@ datatype_factory::datatype_factory(ast_manager & m, model_core & md):
}
expr * datatype_factory::get_some_value(sort * s) {
+ if (!m_util.is_datatype(s))
+ return m_model.get_some_value(s);
value_set * set = nullptr;
if (m_sort2value_set.find(s, set) && !set->empty())
return *(set->begin());
@@ -77,6 +79,8 @@ bool datatype_factory::is_subterm_of_last_value(app* e) {
It also updates m_last_fresh_value
*/
expr * datatype_factory::get_almost_fresh_value(sort * s) {
+ if (!m_util.is_datatype(s))
+ return m_model.get_some_value(s);
value_set * set = get_value_set(s);
if (set->empty()) {
expr * val = get_some_value(s);
@@ -136,6 +140,8 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) {
expr * datatype_factory::get_fresh_value(sort * s) {
+ if (!m_util.is_datatype(s))
+ return m_model.get_fresh_value(s);
TRACE("datatype", tout << "generating fresh value for: " << s->get_name() << "\n";);
value_set * set = get_value_set(s);
// Approach 0)
@@ -162,7 +168,9 @@ expr * datatype_factory::get_fresh_value(sort * s) {
unsigned num = constructor->get_arity();
for (unsigned i = 0; i < num; i++) {
sort * s_arg = constructor->get_domain(i);
- if (!found_fresh_arg && (!m_util.is_recursive(s) || !m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) {
+ if (!found_fresh_arg &&
+ !m_util.is_recursive_array(s_arg) &&
+ (!m_util.is_recursive(s) || !m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) {
expr * new_arg = m_model.get_fresh_value(s_arg);
if (new_arg != nullptr) {
found_fresh_arg = true;
@@ -191,7 +199,7 @@ expr * datatype_factory::get_fresh_value(sort * s) {
// search for constructor...
unsigned num_iterations = 0;
if (m_util.is_recursive(s)) {
- while(true) {
+ while (true) {
++num_iterations;
TRACE("datatype", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
ptr_vector const & constructors = *m_util.get_datatype_constructors(s);
@@ -207,15 +215,15 @@ expr * datatype_factory::get_fresh_value(sort * s) {
<< m_util.are_siblings(s, s_arg) << " is_datatype "
<< m_util.is_datatype(s_arg) << " found_sibling "
<< found_sibling << "\n";);
- if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) {
+ if (!found_sibling && m_util.are_siblings(s, s_arg)) {
found_sibling = true;
expr * maybe_new_arg = nullptr;
- if (num_iterations <= 1) {
- maybe_new_arg = get_almost_fresh_value(s_arg);
- }
- else {
+ if (!m_util.is_datatype(s_arg))
+ maybe_new_arg = m_model.get_fresh_value(s_arg);
+ else if (num_iterations <= 1)
+ maybe_new_arg = get_almost_fresh_value(s_arg);
+ else
maybe_new_arg = get_fresh_value(s_arg);
- }
if (!maybe_new_arg) {
TRACE("datatype",
tout << "no argument found for " << mk_pp(s_arg, m_manager) << "\n";);
diff --git a/src/model/model.cpp b/src/model/model.cpp
index 982cabdde..06ad4028d 100644
--- a/src/model/model.cpp
+++ b/src/model/model.cpp
@@ -24,6 +24,7 @@ Revision History:
#include "ast/rewriter/th_rewriter.h"
#include "ast/array_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
+#include "ast/recfun_decl_plugin.h"
#include "ast/well_sorted.h"
#include "ast/used_symbols.h"
#include "ast/for_each_expr.h"
@@ -582,3 +583,32 @@ void model::reset_eval_cache() {
m_mev.reset();
}
+void model::add_rec_funs() {
+ recfun::util u(m);
+ func_decl_ref_vector recfuns = u.get_rec_funs();
+ for (func_decl* f : recfuns) {
+ auto& def = u.get_def(f);
+ expr* rhs = def.get_rhs();
+ if (!rhs)
+ continue;
+ if (has_interpretation(f))
+ continue;
+ if (f->get_arity() == 0) {
+ register_decl(f, rhs);
+ continue;
+ }
+
+ func_interp* fi = alloc(func_interp, m, f->get_arity());
+ // reverse argument order so that variable 0 starts at the beginning.
+ expr_ref_vector subst(m);
+ for (unsigned i = 0; i < f->get_arity(); ++i) {
+ subst.push_back(m.mk_var(i, f->get_domain(i)));
+ }
+ var_subst sub(m, true);
+ expr_ref bodyr = sub(rhs, subst);
+
+ fi->set_else(bodyr);
+ register_decl(f, fi);
+ }
+ TRACE("model", tout << *this << "\n";);
+}
diff --git a/src/model/model.h b/src/model/model.h
index ea4a38fdd..8183c5a0e 100644
--- a/src/model/model.h
+++ b/src/model/model.h
@@ -108,6 +108,7 @@ public:
void reset_eval_cache();
bool has_solver();
void set_solver(expr_solver* solver);
+ void add_rec_funs();
class scoped_model_completion {
bool m_old_completion;
diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h
index 1e19d05c2..044260f12 100644
--- a/src/muz/base/dl_rule.h
+++ b/src/muz/base/dl_rule.h
@@ -313,7 +313,6 @@ namespace datalog {
static unsigned get_obj_size(unsigned n) { return sizeof(rule) + n * sizeof(app *); }
rule() : m_ref_cnt(0), m_name(symbol::null) {}
- ~rule() {}
void deallocate(ast_manager & m);
diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h
index 147fc26f1..909539a85 100644
--- a/src/muz/rel/dl_base.h
+++ b/src/muz/rel/dl_base.h
@@ -178,7 +178,7 @@ namespace datalog {
class base_fn {
public:
- base_fn() {}
+ base_fn() = default;
virtual ~base_fn() {}
private:
//private and undefined copy constructor and operator= to avoid copying
@@ -219,8 +219,6 @@ namespace datalog {
*/
class mutator_fn : public base_fn {
public:
- ~mutator_fn() override {}
-
virtual void operator()(base_object & t) = 0;
virtual bool supports_attachment(base_object& other) { return false; }
diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h
index 69459e920..8f852f0ba 100644
--- a/src/muz/rel/dl_bound_relation.h
+++ b/src/muz/rel/dl_bound_relation.h
@@ -94,7 +94,6 @@ namespace datalog {
struct uint_set2 {
uint_set lt;
uint_set le;
- uint_set2() {}
bool operator==(const uint_set2& other) const {
return other.lt == lt && other.le == le;
}
diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h
index 22f8b5e38..b62da0766 100644
--- a/src/muz/spacer/spacer_context.h
+++ b/src/muz/spacer/spacer_context.h
@@ -235,7 +235,6 @@ class pred_transformer {
public:
frames (pred_transformer &pt) : m_pt (pt),
m_size(0), m_sorted (true) {}
- ~frames() {}
void simplify_formulas ();
pred_transformer& pt() const {return m_pt;}
@@ -356,7 +355,6 @@ class pred_transformer {
rule2ptrule m_rules;
tag2ptrule m_tags;
public:
- pt_rules() {}
~pt_rules() {for (auto &kv : m_rules) {dealloc(kv.m_value);}}
bool find_by_rule(const datalog::rule &r, pt_rule* &ptr) {
@@ -439,7 +437,6 @@ class pred_transformer {
public:
pred_transformer(context& ctx, manager& pm, func_decl* head);
- ~pred_transformer() {}
inline bool use_native_mbp ();
bool mk_mdl_rf_consistent(const datalog::rule *r, model &mdl);
@@ -825,7 +822,6 @@ class pob_queue {
public:
pob_queue(): m_root(nullptr), m_max_level(0), m_min_depth(0) {}
- ~pob_queue() {}
void reset();
pob* top();
diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp
index eab037bd2..776502541 100644
--- a/src/opt/opt_context.cpp
+++ b/src/opt/opt_context.cpp
@@ -681,6 +681,8 @@ namespace opt {
void context::update_solver() {
sat_params p(m_params);
+ if (p.euf())
+ return;
if (!p.euf()) {
if (!m_enable_sat || !probe_fd()) {
return;
diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h
index 83a5e5125..07e4ed678 100644
--- a/src/parsers/smt2/smt2scanner.h
+++ b/src/parsers/smt2/smt2scanner.h
@@ -75,9 +75,7 @@ namespace smt2 {
EOF_TOKEN
};
- scanner(cmd_context & ctx, std::istream& stream, bool interactive = false);
-
- ~scanner() {}
+ scanner(cmd_context & ctx, std::istream& stream, bool interactive = false);
int get_line() const { return m_line; }
int get_pos() const { return m_pos; }
diff --git a/src/parsers/util/scanner.h b/src/parsers/util/scanner.h
index bd1b29c33..a0beaeff3 100644
--- a/src/parsers/util/scanner.h
+++ b/src/parsers/util/scanner.h
@@ -39,8 +39,6 @@ public:
scanner(std::istream& stream, std::ostream& err, bool smt2, bool bv_token=false);
- ~scanner() {}
-
int get_line() const { return m_line; }
int get_pos() const { return m_pos; }
@@ -86,5 +84,3 @@ private:
token read_bv_literal();
bool state_ok();
};
-
-
diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp
index eb394c59f..fb07ae450 100644
--- a/src/qe/mbp/mbp_arith.cpp
+++ b/src/qe/mbp/mbp_arith.cpp
@@ -281,9 +281,9 @@ namespace mbp {
obj_map tids;
expr_ref_vector pinned(m);
unsigned j = 0;
- TRACE("qe", tout << "vars: " << vars << "\nfmls: " << fmls << "\n";);
- for (unsigned i = 0; i < fmls.size(); ++i) {
- expr * fml = fmls.get(i);
+ TRACE("qe", tout << "vars: " << vars << "\nfmls: " << fmls << "\n";
+ for (expr* f : fmls) tout << mk_pp(f, m) << " := " << model(f) << "\n";);
+ for (expr* fml : fmls) {
if (!linearize(mbo, eval, fml, fmls, tids)) {
TRACE("qe", tout << "could not linearize: " << mk_pp(fml, m) << "\n";);
fmls[j++] = fml;
diff --git a/src/qe/mbp/mbp_plugin.cpp b/src/qe/mbp/mbp_plugin.cpp
index 2731fc5e2..af1043593 100644
--- a/src/qe/mbp/mbp_plugin.cpp
+++ b/src/qe/mbp/mbp_plugin.cpp
@@ -102,6 +102,8 @@ namespace mbp {
model_evaluator eval(model);
eval.set_expand_array_equalities(true);
TRACE("qe", tout << fmls << "\n";);
+ DEBUG_CODE(for (expr* fml : fmls) { CTRACE("qe", m.is_false(eval(fml)), tout << mk_pp(fml, m) << " is false\n";); SASSERT(!m.is_false(eval(fml))); });
+
for (unsigned i = 0; i < fmls.size(); ++i) {
expr* fml = fmls.get(i), * nfml, * f1, * f2, * f3;
SASSERT(m.is_bool(fml));
diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h
index 58f3953a0..eb5fea442 100644
--- a/src/sat/dimacs.h
+++ b/src/sat/dimacs.h
@@ -63,7 +63,6 @@ namespace dimacs {
unsigned m_node_id{ 0 };
std::string m_name;
unsigned_vector m_args;
- drat_record() {}
};
struct drat_pp {
@@ -111,6 +110,3 @@ namespace dimacs {
};
};
-
-
-
diff --git a/src/sat/sat_aig_finder.h b/src/sat/sat_aig_finder.h
index 83e8fcaf4..0928e3c0a 100644
--- a/src/sat/sat_aig_finder.h
+++ b/src/sat/sat_aig_finder.h
@@ -52,7 +52,6 @@ namespace sat {
public:
aig_finder(solver& s);
- ~aig_finder() {}
void set(std::function const& f) { m_on_aig = f; }
void set(std::function const& f) { m_on_if = f; }
void operator()(clause_vector& clauses);
diff --git a/src/sat/sat_anf_simplifier.h b/src/sat/sat_anf_simplifier.h
index d30428311..0f140d5ab 100644
--- a/src/sat/sat_anf_simplifier.h
+++ b/src/sat/sat_anf_simplifier.h
@@ -111,7 +111,6 @@ namespace sat {
public:
anf_simplifier(solver& s) : s(s), m_eval_ts(0) {}
- ~anf_simplifier() {}
void operator()();
void set(config const& cfg) { m_config = cfg; }
diff --git a/src/sat/sat_binspr.h b/src/sat/sat_binspr.h
index 82a5a128c..f533ff489 100644
--- a/src/sat/sat_binspr.h
+++ b/src/sat/sat_binspr.h
@@ -97,8 +97,6 @@ namespace sat {
memset(m_false, 0, sizeof(unsigned) * max_lits);
}
- ~binspr() {}
-
void operator()();
void updt_params(params_ref const& p) {}
diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h
index b03518065..f35f6a58b 100644
--- a/src/sat/sat_extension.h
+++ b/src/sat/sat_extension.h
@@ -128,6 +128,7 @@ namespace sat {
std::function& pb) {
return false;
}
+ virtual bool is_pb() { return false; }
};
};
diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp
index 433750369..0b3c2f7c9 100644
--- a/src/sat/sat_local_search.cpp
+++ b/src/sat/sat_local_search.cpp
@@ -380,16 +380,14 @@ namespace sat {
if (m_config.phase_sticky()) {
unsigned v = 0;
- for (var_info& vi : m_vars) {
+ for (var_info& vi : m_vars)
vi.m_bias = s.m_phase[v++] ? 98 : 2;
- }
}
// copy units
unsigned trail_sz = s.init_trail_size();
- for (unsigned i = 0; i < trail_sz; ++i) {
+ for (unsigned i = 0; i < trail_sz; ++i)
add_clause(1, s.m_trail.data() + i);
- }
// copy binary clauses
{
@@ -410,9 +408,8 @@ namespace sat {
}
// copy clauses
- for (clause* c : s.m_clauses) {
+ for (clause* c : s.m_clauses)
add_clause(c->size(), c->begin());
- }
m_num_non_binary_clauses = s.m_clauses.size();
@@ -422,7 +419,7 @@ namespace sat {
[&](unsigned sz, literal const* c, unsigned k) { add_cardinality(sz, c, k); };
std::function pb =
[&](unsigned sz, literal const* c, unsigned const* coeffs, unsigned k) { add_pb(sz, c, coeffs, k); };
- if (ext && !ext->extract_pb(card, pb))
+ if (ext && (!ext->is_pb() || !ext->extract_pb(card, pb)))
throw default_exception("local search is incomplete with extensions beyond PB");
if (_init) {
diff --git a/src/sat/sat_lut_finder.h b/src/sat/sat_lut_finder.h
index 62f99f7f7..d51f40388 100644
--- a/src/sat/sat_lut_finder.h
+++ b/src/sat/sat_lut_finder.h
@@ -69,7 +69,6 @@ namespace sat {
lut_finder(solver& s) : s(s), m_max_lut_size(5) {
memset(m_masks, 0, sizeof(uint64_t)*7);
}
- ~lut_finder() {}
void set(std::function& f) { m_on_lut = f; }
diff --git a/src/sat/sat_npn3_finder.h b/src/sat/sat_npn3_finder.h
index f3285e4e9..e7364e16d 100644
--- a/src/sat/sat_npn3_finder.h
+++ b/src/sat/sat_npn3_finder.h
@@ -115,7 +115,6 @@ namespace sat {
public:
npn3_finder(solver& s);
- ~npn3_finder() {}
void set_on_mux(std::function const& f) { m_on_mux = f; }
void set_on_maj(std::function const& f) { m_on_maj = f; }
void set_on_orand(std::function const& f) { m_on_orand = f; }
diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h
index 3693cf323..68266760b 100644
--- a/src/sat/sat_parallel.h
+++ b/src/sat/sat_parallel.h
@@ -41,7 +41,6 @@ namespace sat {
unsigned get_length(unsigned index) const { return m_vectors[index+1]; }
unsigned const* get_ptr(unsigned index) const { return m_vectors.data() + index + 2; }
public:
- vector_pool() {}
void reserve(unsigned num_owners, unsigned sz);
void begin_add_vector(unsigned owner, unsigned n);
void end_add_vector();
diff --git a/src/sat/sat_prob.h b/src/sat/sat_prob.h
index 048fc448c..305e76b8b 100644
--- a/src/sat/sat_prob.h
+++ b/src/sat/sat_prob.h
@@ -31,9 +31,8 @@ namespace sat {
class prob : public i_local_search {
struct clause_info {
- clause_info(): m_trues(0), m_num_trues(0) {}
- unsigned m_trues; // set of literals that are true
- unsigned m_num_trues; // size of true set
+ unsigned m_trues = 0; // set of literals that are true
+ unsigned m_num_trues = 0; // size of true set
bool is_true() const { return m_num_trues > 0; }
void add(literal lit) { ++m_num_trues; m_trues += lit.index(); }
void del(literal lit) { SASSERT(m_num_trues > 0); --m_num_trues; m_trues -= lit.index(); }
@@ -129,8 +128,6 @@ namespace sat {
void add(unsigned sz, literal const* c);
public:
- prob() {}
-
~prob() override;
lbool check(unsigned sz, literal const* assumptions, parallel* p) override;
diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp
index bbab83067..d923014c1 100644
--- a/src/sat/sat_solver.cpp
+++ b/src/sat/sat_solver.cpp
@@ -141,6 +141,7 @@ namespace sat {
m_participated.reset();
m_canceled.reset();
m_reasoned.reset();
+ m_case_split_queue.reset();
m_simplifier.reset_todos();
m_qhead = 0;
m_trail.reset();
@@ -1029,7 +1030,7 @@ namespace sat {
return false;
} while (m_qhead < m_trail.size());
- if (m_ext && !is_probing())
+ if (m_ext && (!is_probing() || at_base_lvl()))
m_ext->unit_propagate();
}
if (m_inconsistent)
@@ -1396,7 +1397,8 @@ namespace sat {
}
};
scoped_ls _ls(*this);
- if (inconsistent()) return l_false;
+ if (inconsistent())
+ return l_false;
scoped_limits scoped_rl(rlimit());
SASSERT(m_local_search);
m_local_search->add(*this);
@@ -3540,7 +3542,7 @@ namespace sat {
else {
set_eliminated(v, true);
if (!is_external(v) || true) {
- m_free_vars.push_back(v);
+ m_free_vars.push_back(v);
}
}
}
@@ -3555,6 +3557,7 @@ namespace sat {
bool_var v = m_free_vars[i];
cleanup_watch(literal(v, false));
cleanup_watch(literal(v, true));
+
}
TRACE("sat",
tout << "clauses to reinit: " << (m_clauses_to_reinit.size() - old_sz) << "\n";
@@ -3573,10 +3576,10 @@ namespace sat {
m_free_vars[j++] = w;
m_free_vars.shrink(j);
- for (bool_var i = v; i < m_justification.size(); ++i) {
- m_case_split_queue.del_var_eh(i);
- m_probing.reset_cache(literal(i, true));
- m_probing.reset_cache(literal(i, false));
+ for (bool_var w = m_justification.size(); w-- > v;) {
+ m_case_split_queue.del_var_eh(w);
+ m_probing.reset_cache(literal(w, true));
+ m_probing.reset_cache(literal(w, false));
}
m_watches.shrink(2*v);
m_assignment.shrink(2*v);
@@ -3599,6 +3602,7 @@ namespace sat {
void solver::pop(unsigned num_scopes) {
if (num_scopes == 0)
return;
+ unsigned free_vars_head = m_free_vars.size();
if (m_ext) {
pop_vars(num_scopes);
m_ext->pop(num_scopes);
@@ -3608,6 +3612,8 @@ namespace sat {
scope & s = m_scopes[new_lvl];
m_inconsistent = false; // TBD: use model seems to make this redundant: s.m_inconsistent;
unassign_vars(s.m_trail_lim, new_lvl);
+ for (unsigned i = m_free_vars.size(); i-- > free_vars_head; )
+ m_case_split_queue.del_var_eh(m_free_vars[i]);
m_scope_lvl -= num_scopes;
reinit_clauses(s.m_clauses_to_reinit_lim);
m_scopes.shrink(new_lvl);
diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp
index f22ef3aec..7999676d6 100644
--- a/src/sat/sat_solver/inc_sat_solver.cpp
+++ b/src/sat/sat_solver/inc_sat_solver.cpp
@@ -1057,7 +1057,7 @@ private:
CTRACE("sat", !m.is_true(tmp),
tout << "Evaluation failed: " << mk_pp(f, m) << " to " << tmp << "\n";
model_smt2_pp(tout, m, *(mdl.get()), 0););
- if (!m.is_true(tmp)) {
+ if (m.is_false(tmp)) {
IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n");
IF_VERBOSE(0, verbose_stream() << "evaluated to " << tmp << "\n");
all_true = false;
diff --git a/src/sat/sat_xor_finder.h b/src/sat/sat_xor_finder.h
index 3e9351af9..d0081653e 100644
--- a/src/sat/sat_xor_finder.h
+++ b/src/sat/sat_xor_finder.h
@@ -62,7 +62,6 @@ namespace sat {
public:
xor_finder(solver& s) : s(s), m_max_xor_size(5) { init_parity(); }
- ~xor_finder() {}
void set(std::function& f) { m_on_xor = f; }
diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp
index 8a7fa431b..7e41aeb46 100644
--- a/src/sat/smt/arith_axioms.cpp
+++ b/src/sat/smt/arith_axioms.cpp
@@ -331,6 +331,8 @@ namespace arith {
}
void solver::new_diseq_eh(euf::th_eq const& e) {
+ ensure_column(e.v1());
+ ensure_column(e.v2());
m_delayed_eqs.push_back(std::make_pair(e, false));
ctx.push(push_back_vector>>(m_delayed_eqs));
}
diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp
index f27edfe06..e59d3f4d7 100644
--- a/src/sat/smt/arith_internalize.cpp
+++ b/src/sat/smt/arith_internalize.cpp
@@ -275,6 +275,9 @@ namespace arith {
else {
if (is_app(n)) {
internalize_args(to_app(n));
+ for (expr* arg : *to_app(n))
+ if (a.is_arith_expr(arg))
+ internalize_term(arg);
}
theory_var v = mk_evar(n);
coeffs[vars.size()] = coeffs[index];
@@ -291,9 +294,8 @@ namespace arith {
st.to_ensure_enode().reset();
for (unsigned i = st.to_ensure_var().size(); i-- > 0; ) {
expr* n = st.to_ensure_var()[i];
- if (is_app(n)) {
+ if (is_app(n))
internalize_term(to_app(n));
- }
}
st.to_ensure_var().reset();
}
@@ -388,7 +390,6 @@ namespace arith {
return true;
}
-
bool solver::internalize_term(expr* term) {
if (!has_var(term))
register_theory_var_in_lar_solver(internalize_def(term));
@@ -424,7 +425,7 @@ namespace arith {
TRACE("arith", tout << mk_pp(t, m) << " " << force << " " << reflect(t) << "\n";);
if (!force && !reflect(t))
return;
- for (expr* arg : *t)
+ for (expr* arg : *t)
e_internalize(arg);
}
@@ -435,8 +436,8 @@ namespace arith {
theory_var v = mk_evar(t);
if (_has_var)
return v;
- theory_var w = mk_evar(n);
internalize_term(n);
+ theory_var w = mk_evar(n);
if (p == 0) {
mk_power0_axioms(t, n);
diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp
index a005b10c7..b33e12038 100644
--- a/src/sat/smt/arith_solver.cpp
+++ b/src/sat/smt/arith_solver.cpp
@@ -76,8 +76,9 @@ namespace arith {
}
bool solver::unit_propagate() {
+ TRACE("arith", tout << "unit propagate\n";);
m_model_is_initialized = false;
- if (!m_new_eq && m_new_bounds.empty() && m_asserted_qhead == m_asserted.size())
+ if (!m_solver->has_changed_columns() && !m_new_eq && m_new_bounds.empty() && m_asserted_qhead == m_asserted.size())
return false;
m_new_eq = false;
@@ -138,26 +139,31 @@ namespace arith {
lp_api::bound_kind k = b.get_bound_kind();
theory_var v = b.get_var();
inf_rational val = b.get_value(is_true);
+ bool same_polarity = b.get_lit().sign() == lit1.sign();
lp_bounds const& bounds = m_bounds[v];
SASSERT(!bounds.empty());
if (bounds.size() == 1) return;
if (m_unassigned_bounds[v] == 0) return;
bool v_is_int = b.is_int();
literal lit2 = sat::null_literal;
- bool find_glb = (is_true == (k == lp_api::lower_t));
+ bool find_glb = (same_polarity == (k == lp_api::lower_t));
TRACE("arith", tout << lit1 << " v" << v << " val " << val << " find_glb: " << find_glb << " is_true: " << is_true << " k: " << k << " is_lower: " << (k == lp_api::lower_t) << "\n";);
if (find_glb) {
rational glb;
api_bound* lb = nullptr;
for (api_bound* b2 : bounds) {
- if (b2 == &b) continue;
+ if (b2 == &b)
+ continue;
rational const& val2 = b2->get_value();
- if (((is_true || v_is_int) ? val2 < val : val2 <= val) && (!lb || glb < val2)) {
+ if (lb && glb >= val2)
+ continue;
+ if (((same_polarity || v_is_int) ? val2 < val : val2 <= val)) {
lb = b2;
glb = val2;
}
}
- if (!lb) return;
+ if (!lb)
+ return;
bool sign = lb->get_bound_kind() != lp_api::lower_t;
lit2 = lb->get_lit();
if (sign)
@@ -167,14 +173,18 @@ namespace arith {
rational lub;
api_bound* ub = nullptr;
for (api_bound* b2 : bounds) {
- if (b2 == &b) continue;
+ if (b2 == &b)
+ continue;
rational const& val2 = b2->get_value();
- if (((is_true || v_is_int) ? val < val2 : val <= val2) && (!ub || val2 < lub)) {
+ if (ub && val2 >= lub)
+ continue;
+ if (((same_polarity || v_is_int) ? val < val2 : val <= val2)) {
ub = b2;
lub = val2;
}
}
- if (!ub) return;
+ if (!ub)
+ return;
bool sign = ub->get_bound_kind() != lp_api::upper_t;
lit2 = ub->get_lit();
if (sign)
@@ -609,11 +619,11 @@ namespace arith {
}
else if (a.is_arith_expr(o)) {
expr_ref_vector args(m);
- for (auto* arg : euf::enode_args(n)) {
- if (m.is_value(arg->get_expr()))
- args.push_back(arg->get_expr());
+ for (auto* arg : *to_app(o)) {
+ if (m.is_value(arg))
+ args.push_back(arg);
else
- args.push_back(values.get(arg->get_root_id()));
+ args.push_back(values.get(ctx.get_enode(arg)->get_root_id()));
}
value = m.mk_app(to_app(o)->get_decl(), args.size(), args.data());
ctx.get_rewriter()(value);
@@ -631,8 +641,11 @@ namespace arith {
return false;
expr* e = n->get_expr();
if (a.is_arith_expr(e) && to_app(e)->get_num_args() > 0) {
- for (auto* arg : euf::enode_args(n))
- dep.add(n, arg);
+ for (auto* arg : *to_app(e)) {
+ auto* earg = expr2enode(arg);
+ if (earg)
+ dep.add(n, earg);
+ }
}
else {
dep.insert(n, nullptr);
diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h
index 17887535d..19164dff6 100644
--- a/src/sat/smt/arith_solver.h
+++ b/src/sat/smt/arith_solver.h
@@ -112,7 +112,7 @@ namespace arith {
}
};
scoped_ptr_vector m_internalize_states;
- unsigned m_internalize_head{ 0 };
+ unsigned m_internalize_head = 0;
class scoped_internalize_state {
solver& m_imp;
@@ -149,10 +149,10 @@ namespace arith {
vector m_columns;
var_coeffs m_left_side; // constraint left side
- lpvar m_one_var { UINT_MAX };
- lpvar m_zero_var { UINT_MAX };
- lpvar m_rone_var { UINT_MAX };
- lpvar m_rzero_var { UINT_MAX };
+ lpvar m_one_var = UINT_MAX;
+ lpvar m_zero_var = UINT_MAX;
+ lpvar m_rone_var = UINT_MAX;
+ lpvar m_rzero_var = UINT_MAX;
enum constraint_source {
inequality_source,
@@ -177,7 +177,7 @@ namespace arith {
vector m_bounds;
unsigned_vector m_unassigned_bounds;
unsigned_vector m_bounds_trail;
- unsigned m_asserted_qhead{ 0 };
+ unsigned m_asserted_qhead = 0;
svector > m_assume_eq_candidates;
unsigned m_assume_eq_head{ 0 };
diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp
index 1db56b3e1..129026b34 100644
--- a/src/sat/smt/array_axioms.cpp
+++ b/src/sat/smt/array_axioms.cpp
@@ -174,14 +174,19 @@ namespace array {
SASSERT(store->get_num_args() == 1 + select->get_num_args());
ptr_buffer sel1_args, sel2_args;
unsigned num_args = select->get_num_args();
- sel1_args.push_back(store);
- sel2_args.push_back(store->get_arg(0));
+ if (select->get_arg(0) != store && expr2enode(select->get_arg(0))->get_root() == expr2enode(store)->get_root())
+ return false;
bool has_diff = false;
for (unsigned i = 1; i < num_args; i++)
has_diff |= expr2enode(select->get_arg(i))->get_root() != expr2enode(store->get_arg(i))->get_root();
if (!has_diff)
return false;
+
+
+ sel1_args.push_back(store);
+ sel2_args.push_back(store->get_arg(0));
+
for (unsigned i = 1; i < num_args; i++) {
sel1_args.push_back(select->get_arg(i));
@@ -191,20 +196,31 @@ namespace array {
expr_ref sel1(a.mk_select(sel1_args), m);
expr_ref sel2(a.mk_select(sel2_args), m);
expr_ref sel_eq_e(m.mk_eq(sel1, sel2), m);
+
+ bool new_prop = false;
+ if (!ctx.get_egraph().find(sel1))
+ new_prop = true;
+ if (!ctx.get_egraph().find(sel2))
+ new_prop = true;
+
euf::enode* s1 = e_internalize(sel1);
euf::enode* s2 = e_internalize(sel2);
TRACE("array",
tout << "select-store " << ctx.bpp(s1) << " " << ctx.bpp(s1->get_root()) << "\n";
tout << "select-store " << ctx.bpp(s2) << " " << ctx.bpp(s2->get_root()) << "\n";);
+
if (s1->get_root() == s2->get_root())
- return false;
+ return new_prop;
- sat::literal sel_eq = mk_literal(sel_eq_e);
- if (s().value(sel_eq) == l_true)
- return false;
+ sat::literal sel_eq = sat::null_literal;
+ auto init_sel_eq = [&]() {
+ if (sel_eq != sat::null_literal)
+ return true;
+ sel_eq = mk_literal(sel_eq_e);
+ return s().value(sel_eq) != l_true;
+ };
- bool new_prop = false;
for (unsigned i = 1; i < num_args; i++) {
expr* idx1 = store->get_arg(i);
expr* idx2 = select->get_arg(i);
@@ -213,11 +229,17 @@ namespace array {
if (r1 == r2)
continue;
if (m.are_distinct(r1->get_expr(), r2->get_expr())) {
- new_prop = true;
- add_clause(sel_eq);
+ if (init_sel_eq() && add_clause(sel_eq))
+ new_prop = true;
break;
}
sat::literal idx_eq = eq_internalize(idx1, idx2);
+ if (s().value(idx_eq) == l_true)
+ continue;
+ if (s().value(idx_eq) == l_undef)
+ new_prop = true;
+ if (!init_sel_eq())
+ break;
if (add_clause(idx_eq, sel_eq))
new_prop = true;
}
diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp
index 850429579..4e6f75c4d 100644
--- a/src/sat/smt/array_solver.cpp
+++ b/src/sat/smt/array_solver.cpp
@@ -269,6 +269,6 @@ namespace array {
bool solver::can_beta_reduce(euf::enode* n) const {
expr* c = n->get_expr();
- return a.is_const(c) || a.is_as_array(c) || a.is_store(c) || is_lambda(c);
+ return a.is_const(c) || a.is_as_array(c) || a.is_store(c) || is_lambda(c) || a.is_map(c);
}
}
diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h
index 3b87d65f3..6cd5274c9 100644
--- a/src/sat/smt/array_solver.h
+++ b/src/sat/smt/array_solver.h
@@ -54,7 +54,6 @@ namespace array {
euf::enode_vector m_lambdas; // equivalent nodes that have beta reduction properties
euf::enode_vector m_parent_lambdas; // parents that have beta reduction properties
euf::enode_vector m_parent_selects; // parents that use array in select position
- var_data() {}
};
diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp
index 5c0061019..ca4841656 100644
--- a/src/sat/smt/bv_delay_internalize.cpp
+++ b/src/sat/smt/bv_delay_internalize.cpp
@@ -73,6 +73,8 @@ namespace bv {
SASSERT(e->get_num_args() >= 2);
expr_ref_vector args(m);
euf::enode* n = expr2enode(e);
+ if (!reflect())
+ return false;
auto r1 = eval_bv(n);
auto r2 = eval_args(n, args);
if (r1 == r2)
@@ -356,6 +358,8 @@ namespace bv {
return internalize_mode::no_delay_i;
if (!get_config().m_bv_delay)
return internalize_mode::no_delay_i;
+ if (!reflect())
+ return internalize_mode::no_delay_i;
internalize_mode mode;
switch (to_app(e)->get_decl_kind()) {
case OP_BMUL:
diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp
index 8e6867dc7..e3c193f5a 100644
--- a/src/sat/smt/bv_internalize.cpp
+++ b/src/sat/smt/bv_internalize.cpp
@@ -137,7 +137,7 @@ namespace bv {
return true;
SASSERT(!n || !n->is_attached_to(get_id()));
- bool suppress_args = !get_config().m_bv_reflect && !m.is_considered_uninterpreted(a->get_decl());
+ bool suppress_args = !reflect() && !m.is_considered_uninterpreted(a->get_decl());
if (!n)
n = mk_enode(e, suppress_args);
@@ -661,12 +661,10 @@ namespace bv {
if (lit0 == sat::null_literal) {
m_bits[v_arg][idx] = lit;
TRACE("bv", tout << "add-bit: " << lit << " " << literal2expr(lit) << "\n";);
- if (arg_sz > 1) {
- atom* a = new (get_region()) atom(lit.var());
- a->m_occs = new (get_region()) var_pos_occ(v_arg, idx);
- insert_bv2a(lit.var(), a);
- ctx.push(mk_atom_trail(lit.var(), *this));
- }
+ atom* a = new (get_region()) atom(lit.var());
+ a->m_occs = new (get_region()) var_pos_occ(v_arg, idx);
+ insert_bv2a(lit.var(), a);
+ ctx.push(mk_atom_trail(lit.var(), *this));
}
else if (lit != lit0) {
add_clause(lit0, ~lit);
diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp
index 2762a1244..4df92596e 100644
--- a/src/sat/smt/bv_solver.cpp
+++ b/src/sat/smt/bv_solver.cpp
@@ -55,6 +55,7 @@ namespace bv {
m_ackerman(*this),
m_bb(m, get_config()),
m_find(*this) {
+ m_bb.set_flat(false);
}
void solver::fixed_var_eh(theory_var v1) {
diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h
index daf21a132..3d15c2cf1 100644
--- a/src/sat/smt/bv_solver.h
+++ b/src/sat/smt/bv_solver.h
@@ -259,6 +259,7 @@ namespace bv {
void assert_bv2int_axiom(app * n);
void assert_int2bv_axiom(app* n);
void assert_ackerman(theory_var v1, theory_var v2);
+ bool reflect() const { return get_config().m_bv_reflect; }
// delay internalize
enum class internalize_mode {
diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp
index 2c01118c9..1eb9d6aef 100644
--- a/src/sat/smt/euf_internalize.cpp
+++ b/src/sat/smt/euf_internalize.cpp
@@ -42,7 +42,7 @@ namespace euf {
if (n) {
if (m.is_bool(e)) {
SASSERT(!s().was_eliminated(n->bool_var()));
- SASSERT(n->bool_var() != UINT_MAX);
+ SASSERT(n->bool_var() != sat::null_bool_var);
return literal(n->bool_var(), sign);
}
TRACE("euf", tout << "non-bool\n";);
@@ -109,11 +109,13 @@ namespace euf {
if (m.is_bool(e))
attach_lit(literal(si.add_bool_var(e), false), e);
- if (!m.is_bool(e) && e->get_sort()->get_family_id() != null_family_id) {
+ if (!m.is_bool(e) && !m.is_uninterp(e->get_sort())) {
auto* e_ext = expr2solver(e);
auto* s_ext = sort2solver(e->get_sort());
if (s_ext && s_ext != e_ext)
s_ext->apply_sort_cnstr(n, e->get_sort());
+ else if (!s_ext && !e_ext && is_app(e))
+ unhandled_function(to_app(e)->get_decl());
}
expr* a = nullptr, * b = nullptr;
if (m.is_eq(e, a, b) && a->get_sort()->get_family_id() != null_family_id) {
@@ -151,7 +153,7 @@ namespace euf {
enode* n = m_egraph.find(e);
if (!n)
n = m_egraph.mk(e, m_generation, 0, nullptr);
- SASSERT(n->bool_var() == UINT_MAX || n->bool_var() == v);
+ SASSERT(n->bool_var() == sat::null_bool_var || n->bool_var() == v);
m_egraph.set_bool_var(n, v);
if (m.is_eq(e) || m.is_or(e) || m.is_and(e) || m.is_not(e))
m_egraph.set_merge_enabled(n, false);
@@ -177,10 +179,13 @@ namespace euf {
void solver::add_not_distinct_axiom(app* e, enode* const* args) {
SASSERT(m.is_distinct(e));
unsigned sz = e->get_num_args();
- if (sz <= 1)
- return;
-
sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id());
+
+ if (sz <= 1) {
+ s().mk_clause(0, nullptr, st);
+ return;
+ }
+
static const unsigned distinct_max_args = 32;
if (sz <= distinct_max_args) {
sat::literal_vector lits;
@@ -193,8 +198,8 @@ namespace euf {
}
s().mk_clause(lits, st);
if (relevancy_enabled())
- add_root(lits.size(), lits.data());
- }
+ add_root(lits);
+ }
else {
// g(f(x_i)) = x_i
// f(x_1) = a + .... + f(x_n) = a >= 2
@@ -228,10 +233,8 @@ namespace euf {
static const unsigned distinct_max_args = 32;
unsigned sz = e->get_num_args();
sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id());
- if (sz <= 1) {
- s().mk_clause(0, nullptr, st);
+ if (sz <= 1)
return;
- }
if (sz <= distinct_max_args) {
for (unsigned i = 0; i < sz; ++i) {
for (unsigned j = i + 1; j < sz; ++j) {
diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp
index 7020ed08c..5ac8e7caa 100644
--- a/src/sat/smt/euf_model.cpp
+++ b/src/sat/smt/euf_model.cpp
@@ -73,16 +73,17 @@ namespace euf {
values2model(deps, mdl);
for (auto* mb : m_solvers)
mb->finalize_model(*mdl);
+ TRACE("model", tout << "created model " << *mdl << "\n";);
validate_model(*mdl);
}
bool solver::include_func_interp(func_decl* f) {
- if (f->is_skolem())
- return false;
if (f->get_family_id() == null_family_id)
return true;
if (f->get_family_id() == m.get_basic_family_id())
return false;
+ if (f->is_skolem())
+ return false;
euf::th_model_builder* mb = func_decl2solver(f);
return mb && mb->include_func_interp(f);
}
@@ -190,7 +191,7 @@ namespace euf {
if (!is_app(e))
continue;
app* a = to_app(e);
- func_decl* f = a->get_decl();
+ func_decl* f = a->get_decl();
if (!include_func_interp(f))
continue;
if (m.is_bool(e) && is_uninterp_const(e) && mdl->get_const_interp(f))
@@ -209,9 +210,12 @@ namespace euf {
mdl->register_decl(f, fi);
}
args.reset();
- for (enode* arg : enode_args(n))
- args.push_back(m_values.get(arg->get_root_id()));
- DEBUG_CODE(for (expr* arg : args) VERIFY(arg););
+ for (expr* arg : *a) {
+ enode* earg = get_enode(arg);
+ args.push_back(m_values.get(earg->get_root_id()));
+ CTRACE("euf", !args.back(), tout << "no value for " << bpp(earg) << "\n";);
+ SASSERT(args.back());
+ }
SASSERT(args.size() == arity);
if (!fi->get_entry(args.data()))
fi->insert_new_entry(args.data(), v);
@@ -227,17 +231,23 @@ namespace euf {
// TODO
}
+ void solver::model_updated(model_ref& mdl) {
+ m_values2root.reset();
+ for (enode* n : m_egraph.nodes())
+ if (n->is_root() && m_values.get(n->get_expr_id()))
+ m_values[n->get_expr_id()] = (*mdl)(n->get_expr());
+ }
+
obj_map const& solver::values2root() {
if (!m_values2root.empty())
return m_values2root;
for (enode* n : m_egraph.nodes())
if (n->is_root() && m_values.get(n->get_expr_id()))
m_values2root.insert(m_values.get(n->get_expr_id()), n);
-#if 0
- for (auto kv : m_values2root) {
- std::cout << mk_pp(kv.m_key, m) << " -> " << bpp(kv.m_value) << "\n";
- }
-#endif
+ TRACE("model",
+ for (auto kv : m_values2root)
+ tout << mk_pp(kv.m_key, m) << " -> " << bpp(kv.m_value) << "\n";);
+
return m_values2root;
}
@@ -246,20 +256,29 @@ namespace euf {
}
void solver::validate_model(model& mdl) {
+ bool first = true;
for (enode* n : m_egraph.nodes()) {
expr* e = n->get_expr();
if (!m.is_bool(e))
continue;
+ if (has_quantifiers(e))
+ continue;
if (!is_relevant(n))
continue;
bool tt = l_true == s().value(n->bool_var());
- if (tt && mdl.is_false(e)) {
- IF_VERBOSE(0, verbose_stream() << "Failed to validate " << bpp(n) << " " << mdl(e) << "\n");
- for (auto* arg : euf::enode_args(n))
- IF_VERBOSE(0, verbose_stream() << bpp(arg) << "\n" << mdl(arg->get_expr()) << "\n");
- }
- if (!tt && mdl.is_true(e))
- IF_VERBOSE(0, verbose_stream() << "Failed to validate " << bpp(n) << " " << mdl(e) << "\n");
+ if (tt && !mdl.is_false(e))
+ continue;
+ if (!tt && !mdl.is_true(e))
+ continue;
+ IF_VERBOSE(0,
+ verbose_stream() << "Failed to validate " << n->bool_var() << " " << bpp(n) << " " << mdl(e) << "\n";
+ for (auto* arg : euf::enode_args(n))
+ verbose_stream() << bpp(arg) << "\n" << mdl(arg->get_expr()) << "\n";);
+ CTRACE("euf", first,
+ tout << "Failed to validate " << n->bool_var() << " " << bpp(n) << " " << mdl(e) << "\n";
+ s().display(tout);
+ tout << mdl << "\n";);
+ first = false;
}
}
diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp
index 51388fa80..f5c05cea9 100644
--- a/src/sat/smt/euf_relevancy.cpp
+++ b/src/sat/smt/euf_relevancy.cpp
@@ -106,8 +106,8 @@ namespace euf {
TRACE("euf",
for (enode* n : m_egraph.nodes())
- if (is_relevant(n))
- tout << "relevant " << mk_bounded_pp(n->get_expr(), m) << "\n";);
- return true;
+ if (is_relevant(n))
+ tout << "relevant " << n->get_expr_id() << " [r" << n->get_root_id() << "]: " << mk_bounded_pp(n->get_expr(), m) << "\n";);
+ return true;
}
}
diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp
index 89779f144..66b373b6f 100644
--- a/src/sat/smt/euf_solver.cpp
+++ b/src/sat/smt/euf_solver.cpp
@@ -294,7 +294,7 @@ namespace euf {
euf::enode* n = m_egraph.find(e);
if (!n)
return;
- bool sign = l.sign();
+ bool sign = l.sign();
m_egraph.set_value(n, sign ? l_false : l_true);
for (auto th : enode_th_vars(n))
m_id2solver[th.get_id()]->asserted(l);
@@ -308,7 +308,7 @@ namespace euf {
euf::enode* nb = n->get_arg(1);
m_egraph.merge(na, nb, c);
}
- else if (n->merge_tf()) {
+ else if (n->merge_tf() || n->value_conflict()) {
euf::enode* nb = sign ? mk_false() : mk_true();
m_egraph.merge(n, nb, c);
}
@@ -332,10 +332,10 @@ namespace euf {
propagated1 = true;
}
- for (auto* s : m_solvers) {
- if (s->unit_propagate())
+ for (unsigned i = 0; i < m_solvers.size(); ++i)
+ if (m_solvers[i]->unit_propagate())
propagated1 = true;
- }
+
if (!propagated1)
break;
propagated = true;
diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h
index ae9ba1488..ac8c41d59 100644
--- a/src/sat/smt/euf_solver.h
+++ b/src/sat/smt/euf_solver.h
@@ -149,7 +149,7 @@ namespace euf {
// model building
expr_ref_vector m_values;
- obj_map m_values2root;
+ obj_map m_values2root;
bool include_func_interp(func_decl* f);
void register_macros(model& mdl);
void dependencies2values(user_sort& us, deps_t& deps, model_ref& mdl);
@@ -357,8 +357,11 @@ namespace euf {
// relevancy
bool relevancy_enabled() const { return get_config().m_relevancy_lvl > 0; }
void add_root(unsigned n, sat::literal const* lits);
+ void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); }
+ void add_root(sat::literal lit) { add_root(1, &lit); }
+ void add_root(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_root(2, lits); }
void add_aux(unsigned n, sat::literal const* lits);
- void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); }
+ void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); }
void track_relevancy(sat::bool_var v);
bool is_relevant(expr* e) const;
bool is_relevant(enode* n) const;
@@ -367,6 +370,7 @@ namespace euf {
// model construction
void update_model(model_ref& mdl);
obj_map const& values2root();
+ void model_updated(model_ref& mdl);
expr* node2value(enode* n) const;
// diagnostics
diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp
index 5904376f0..ef2fd731c 100644
--- a/src/sat/smt/fpa_solver.cpp
+++ b/src/sat/smt/fpa_solver.cpp
@@ -122,6 +122,50 @@ namespace fpa {
n = mk_enode(e, false);
SASSERT(!n->is_attached_to(get_id()));
mk_var(n);
+ TRACE("fp", tout << "post: " << mk_bounded_pp(e, m) << "\n";);
+ m_nodes.push_back(std::tuple(n, sign, root));
+ ctx.push(push_back_trail(m_nodes));
+ return true;
+ }
+
+ void solver::apply_sort_cnstr(enode* n, sort* s) {
+ TRACE("t_fpa", tout << "apply sort cnstr for: " << mk_ismt2_pp(n->get_expr(), m) << "\n";);
+ SASSERT(s->get_family_id() == get_id());
+ SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s));
+ SASSERT(m_fpa_util.is_float(n->get_expr()) || m_fpa_util.is_rm(n->get_expr()));
+ SASSERT(n->get_decl()->get_range() == s);
+
+ if (is_attached_to_var(n))
+ return;
+ attach_new_th_var(n);
+
+ expr* owner = n->get_expr();
+
+ if (m_fpa_util.is_rm(s) && !m_fpa_util.is_bv2rm(owner)) {
+ // For every RM term, we need to make sure that it's
+ // associated bit-vector is within the valid range.
+ expr_ref valid(m), limit(m);
+ limit = m_bv_util.mk_numeral(4, 3);
+ valid = m_bv_util.mk_ule(m_converter.wrap(owner), limit);
+ add_unit(mk_literal(valid));
+ }
+ activate(owner);
+ }
+
+ bool solver::unit_propagate() {
+
+ if (m_nodes.size() <= m_nodes_qhead)
+ return false;
+ ctx.push(value_trail(m_nodes_qhead));
+ for (; m_nodes_qhead < m_nodes.size(); ++m_nodes_qhead)
+ unit_propagate(m_nodes[m_nodes_qhead]);
+ return true;
+ }
+
+ void solver::unit_propagate(std::tuple const& t) {
+ auto [n, sign, root] = t;
+ expr* e = n->get_expr();
+ app* a = to_app(e);
if (m.is_bool(e)) {
sat::literal atom(ctx.get_si().add_bool_var(e), false);
atom = ctx.attach_lit(atom, e);
@@ -151,31 +195,7 @@ namespace fpa {
break;
}
}
- return true;
- }
- void solver::apply_sort_cnstr(enode* n, sort* s) {
- TRACE("t_fpa", tout << "apply sort cnstr for: " << mk_ismt2_pp(n->get_expr(), m) << "\n";);
- SASSERT(s->get_family_id() == get_id());
- SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s));
- SASSERT(m_fpa_util.is_float(n->get_expr()) || m_fpa_util.is_rm(n->get_expr()));
- SASSERT(n->get_decl()->get_range() == s);
-
- if (is_attached_to_var(n))
- return;
- attach_new_th_var(n);
-
- expr* owner = n->get_expr();
-
- if (m_fpa_util.is_rm(s) && !m_fpa_util.is_bv2rm(owner)) {
- // For every RM term, we need to make sure that it's
- // associated bit-vector is within the valid range.
- expr_ref valid(m), limit(m);
- limit = m_bv_util.mk_numeral(4, 3);
- valid = m_bv_util.mk_ule(m_converter.wrap(owner), limit);
- add_unit(mk_literal(valid));
- }
- activate(owner);
}
void solver::activate(expr* n) {
diff --git a/src/sat/smt/fpa_solver.h b/src/sat/smt/fpa_solver.h
index 9f0d8ae36..795abdfdd 100644
--- a/src/sat/smt/fpa_solver.h
+++ b/src/sat/smt/fpa_solver.h
@@ -36,6 +36,8 @@ namespace fpa {
bv_util & m_bv_util;
arith_util & m_arith_util;
obj_map m_conversions;
+ svector> m_nodes;
+ unsigned m_nodes_qhead = 0;
bool visit(expr* e) override;
bool visited(expr* e) override;
@@ -45,6 +47,7 @@ namespace fpa {
sat::literal_vector mk_side_conditions();
void attach_new_th_var(enode* n);
void activate(expr* e);
+ void unit_propagate(std::tuple const& t);
void ensure_equality_relation(theory_var x, theory_var y);
public:
@@ -67,7 +70,7 @@ namespace fpa {
bool add_dep(euf::enode* n, top_sort& dep) override;
void finalize_model(model& mdl) override;
- bool unit_propagate() override { return false; }
+ bool unit_propagate() override;
void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override { UNREACHABLE(); }
sat::check_result check() override { return sat::check_result::CR_DONE; }
diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp
index 4b5d63cf4..33fd1c48d 100644
--- a/src/sat/smt/pb_solver.cpp
+++ b/src/sat/smt/pb_solver.cpp
@@ -132,7 +132,6 @@ namespace pb {
remove_constraint(p, "is tight");
}
else {
-
unsigned sz = p.size();
clear_watch(p);
unsigned j = 0;
@@ -1470,7 +1469,6 @@ namespace pb {
return true;
}
else if (c.lit() != sat::null_literal && value(c.lit()) != l_true) {
- // else if (c.lit() != sat::null_literal && value(c.lit()) == l_false) {
return true;
}
else {
@@ -2025,7 +2023,7 @@ namespace pb {
unit_strengthen();
cleanup_clauses();
cleanup_constraints();
- update_pure();
+
count++;
}
while (count < 10 && (m_simplify_change || trail_sz < s().init_trail_size()));
@@ -2047,41 +2045,6 @@ namespace pb {
// if (s().m_clauses.size() < 80000) lp_lookahead_reduction();
}
- /*
- * ~lit does not occur in clauses
- * ~lit is only in one constraint use list
- * lit == C
- * -> ignore assignments to ~lit for C
- *
- * ~lit does not occur in clauses
- * lit is only in one constraint use list
- * lit == C
- * -> negate: ~lit == ~C
- */
- void solver::update_pure() {
- //return;
- for (constraint* cp : m_constraints) {
- literal lit = cp->lit();
- if (lit != sat::null_literal &&
- !cp->is_pure() &&
- value(lit) == l_undef &&
- get_wlist(~lit).size() == 1 &&
- m_clause_use_list.get(lit).empty()) {
- clear_watch(*cp);
- cp->negate();
- lit.neg();
- }
- if (lit != sat::null_literal &&
- !cp->is_pure() &&
- m_cnstr_use_list[(~lit).index()].size() == 1 &&
- get_wlist(lit).size() == 1 &&
- m_clause_use_list.get(~lit).empty()) {
- cp->set_pure();
- get_wlist(~lit).erase(sat::watched(cp->cindex())); // just ignore assignments to false
- }
- }
- }
-
void solver::mutex_reduction() {
literal_vector lits;
for (unsigned v = 0; v < s().num_vars(); ++v) {
diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h
index a3b75300a..c19facf34 100644
--- a/src/sat/smt/pb_solver.h
+++ b/src/sat/smt/pb_solver.h
@@ -211,6 +211,7 @@ namespace pb {
unsigned next_id() { return m_constraint_id++; }
void set_non_learned(constraint& c);
double get_reward(literal l, sat::ext_justification_idx idx, sat::literal_occs_fun& occs) const override;
+ bool is_pb() override { return true; }
// cardinality
lbool add_assign(card& c, literal lit);
diff --git a/src/sat/smt/q_clause.h b/src/sat/smt/q_clause.h
index 6cdf2a8f4..149b9ac94 100644
--- a/src/sat/smt/q_clause.h
+++ b/src/sat/smt/q_clause.h
@@ -56,8 +56,8 @@ namespace q {
vector m_lits;
quantifier_ref m_q;
sat::literal m_literal;
- q::quantifier_stat* m_stat { nullptr };
- binding* m_bindings { nullptr };
+ q::quantifier_stat* m_stat = nullptr;
+ binding* m_bindings = nullptr;
clause(ast_manager& m, unsigned idx): m_index(idx), m_q(m) {}
diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp
index 74856ccbe..3dfa62422 100644
--- a/src/sat/smt/q_ematch.cpp
+++ b/src/sat/smt/q_ematch.cpp
@@ -8,7 +8,7 @@ Module Name:
Abstract:
E-matching quantifier instantiation plugin
-
+
Author:
Nikolaj Bjorner (nbjorner) 2021-01-24
@@ -213,6 +213,14 @@ namespace q {
unsigned sz = sizeof(binding) + sizeof(euf::enode* const*)*n;
void* mem = ctx.get_region().allocate(sz);
return new (mem) binding(pat, max_generation, min_top, max_top);
+ }
+
+ euf::enode* const* ematch::alloc_binding(clause& c, euf::enode* const* _binding) {
+ unsigned sz = sizeof(euf::enode* const*) * c.num_decls();
+ euf::enode** binding = (euf::enode**)ctx.get_region().allocate(sz);
+ for (unsigned i = 0; i < c.num_decls(); ++i)
+ binding[i] = _binding[i];
+ return binding;
}
void ematch::add_binding(clause& c, app* pat, euf::enode* const* _binding, unsigned max_generation, unsigned min_top, unsigned max_top) {
@@ -229,11 +237,12 @@ namespace q {
TRACE("q", tout << "on-binding " << mk_pp(q, m) << "\n";);
unsigned idx = m_q2clauses[q];
clause& c = *m_clauses[idx];
- if (!propagate(_binding, max_generation, c))
+ bool new_propagation = false;
+ if (!propagate(false, _binding, max_generation, c, new_propagation))
add_binding(c, pat, _binding, max_generation, min_gen, max_gen);
}
- bool ematch::propagate(euf::enode* const* binding, unsigned max_generation, clause& c) {
+ bool ematch::propagate(bool is_owned, euf::enode* const* binding, unsigned max_generation, clause& c, bool& propagated) {
TRACE("q", c.display(ctx, tout) << "\n";);
unsigned idx = UINT_MAX;
lbool ev = m_eval(binding, c, idx);
@@ -251,6 +260,8 @@ namespace q {
}
if (ev == l_undef && max_generation > m_generation_propagation_threshold)
return false;
+ if (!is_owned)
+ binding = alloc_binding(c, binding);
auto j_idx = mk_justification(idx, c, binding);
if (ev == l_false) {
++m_stats.m_num_conflicts;
@@ -260,6 +271,7 @@ namespace q {
++m_stats.m_num_propagations;
ctx.propagate(instantiate(c, binding, c[idx]), j_idx);
}
+ propagated = true;
return true;
}
@@ -372,6 +384,7 @@ namespace q {
clause* cl = alloc(clause, m, m_clauses.size());
cl->m_literal = ctx.mk_literal(_q);
quantifier_ref q(_q, m);
+ q = m_qs.flatten(q);
if (is_exists(q)) {
cl->m_literal.neg();
expr_ref body(mk_not(m, q->get_expr()), m);
@@ -479,10 +492,8 @@ namespace q {
continue;
do {
- if (propagate(b->m_nodes, b->m_max_generation, c)) {
+ if (propagate(true, b->m_nodes, b->m_max_generation, c, propagated))
to_remove.push_back(b);
- propagated = true;
- }
else if (flush) {
instantiate(*b, c);
to_remove.push_back(b);
diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h
index 39ba72f27..443b9d947 100644
--- a/src/sat/smt/q_ematch.h
+++ b/src/sat/smt/q_ematch.h
@@ -81,6 +81,7 @@ namespace q {
unsigned_vector m_clause_queue;
binding* alloc_binding(unsigned n, app* pat, unsigned max_generation, unsigned min_top, unsigned max_top);
+ euf::enode* const* alloc_binding(clause& c, euf::enode* const* _binding);
void add_binding(clause& c, app* pat, euf::enode* const* _binding, unsigned max_generation, unsigned min_top, unsigned max_top);
sat::ext_justification_idx mk_justification(unsigned idx, clause& c, euf::enode* const* b);
@@ -130,7 +131,7 @@ namespace q {
void add_instantiation(clause& c, binding& b, sat::literal lit);
- bool propagate(euf::enode* const* binding, unsigned max_generation, clause& c);
+ bool propagate(bool is_owned, euf::enode* const* binding, unsigned max_generation, clause& c, bool& new_propagation);
std::ostream& display(std::ostream& out) const;
diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp
index 8f03d4d8b..5e5cc83b8 100644
--- a/src/sat/smt/q_eval.cpp
+++ b/src/sat/smt/q_eval.cpp
@@ -157,6 +157,7 @@ namespace q {
expr* t = todo.back();
SASSERT(!is_ground(t) || ctx.get_egraph().find(t));
if (is_ground(t)) {
+ m_mark.mark(t);
m_eval.setx(t->get_id(), ctx.get_egraph().find(t), nullptr);
SASSERT(m_eval[t->get_id()]);
todo.pop_back();
@@ -277,6 +278,7 @@ namespace q {
void eval::explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing) {
+ scoped_mark_reset _sr(*this);
unsigned l_idx = 0;
clause& c = j.m_clause;
for (; l_idx < c.size(); ++l_idx) {
diff --git a/src/sat/smt/q_mam.cpp b/src/sat/smt/q_mam.cpp
index 6a7b8e1e4..000f76879 100644
--- a/src/sat/smt/q_mam.cpp
+++ b/src/sat/smt/q_mam.cpp
@@ -1991,7 +1991,8 @@ namespace q {
TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout););
init(t);
if (t->filter_candidates()) {
- for (enode* app : t->get_candidates()) {
+ for (unsigned i = 0; i < t->get_candidates().size(); ++i) {
+ enode* app = t->get_candidates()[i];
TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_expr(), m) << "\n";);
if (!app->is_marked1() && app->is_cgr()) {
if (ctx.resource_limits_exceeded() || !execute_core(t, app))
@@ -2005,7 +2006,8 @@ namespace q {
}
}
else {
- for (enode* app : t->get_candidates()) {
+ for (unsigned i = 0; i < t->get_candidates().size(); ++i) {
+ enode* app = t->get_candidates()[i];
TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_expr(), m) << "\n";);
if (app->is_cgr()) {
TRACE("trigger_bug", tout << "is_cgr\n";);
@@ -2254,6 +2256,8 @@ namespace q {
#endif
// It doesn't make sense to process an irrelevant enode.
TRACE("mam_execute_core", tout << "EXEC " << t->get_root_lbl()->get_name() << "\n";);
+ if (!ctx.is_relevant(n))
+ return false;
SASSERT(ctx.is_relevant(n));
m_pattern_instances.reset();
m_min_top_generation.reset();
@@ -3030,6 +3034,7 @@ namespace q {
ptr_vector m_tmp_trees;
ptr_vector m_tmp_trees_to_delete;
ptr_vector m_to_match;
+ unsigned m_to_match_head = 0;
typedef std::pair qp_pair;
svector m_new_patterns; // recently added patterns
@@ -3059,16 +3064,14 @@ namespace q {
enode * m_other { nullptr }; // temp field
bool m_check_missing_instances { false };
- class reset_to_match : public trail {
+ class pop_to_match : public trail {
mam_impl& i;
public:
- reset_to_match(mam_impl& i):i(i) {}
+ pop_to_match(mam_impl& i):i(i) {}
void undo() override {
- if (i.m_to_match.empty())
- return;
- for (code_tree* t : i.m_to_match)
- t->reset_candidates();
- i.m_to_match.reset();
+ code_tree* t = i.m_to_match.back();
+ t->reset_candidates();
+ i.m_to_match.pop_back();
}
};
@@ -3092,12 +3095,12 @@ namespace q {
}
void add_candidate(code_tree * t, enode * app) {
- if (t != nullptr) {
+ if (t) {
TRACE("mam_candidate", tout << "adding candidate:\n" << mk_ll_pp(app->get_expr(), m););
- if (m_to_match.empty())
- ctx.push(reset_to_match(*this));
- if (!t->has_candidates())
+ if (!t->has_candidates()) {
+ ctx.push(pop_to_match(*this));
m_to_match.push_back(t);
+ }
t->add_candidate(app);
}
}
@@ -3702,9 +3705,12 @@ namespace q {
SASSERT(tmp_tree != 0);
SASSERT(!m_egraph.enodes_of(lbl).empty());
m_interpreter.init(tmp_tree);
- for (enode * app : m_egraph.enodes_of(lbl))
+ auto& nodes = m_egraph.enodes_of(lbl);
+ for (unsigned i = 0; i < nodes.size(); ++i) {
+ enode* app = nodes[i];
if (ctx.is_relevant(app))
m_interpreter.execute_core(tmp_tree, app);
+ }
m_tmp_trees[lbl_id] = nullptr;
dealloc(tmp_tree);
}
@@ -3755,7 +3761,6 @@ namespace q {
void reset() override {
m_trees.reset();
- m_to_match.reset();
m_new_patterns.reset();
m_is_plbl.reset();
m_is_clbl.reset();
@@ -3773,12 +3778,16 @@ namespace q {
void propagate() override {
TRACE("trigger_bug", tout << "match\n"; display(tout););
- for (code_tree* t : m_to_match) {
- SASSERT(t->has_candidates());
- m_interpreter.execute(t);
- t->reset_candidates();
+ if (m_to_match_head >= m_to_match.size())
+ return;
+ ctx.push(value_trail(m_to_match_head));
+ for (; m_to_match_head < m_to_match.size(); ++m_to_match_head) {
+ code_tree* t = m_to_match[m_to_match_head];
+ if (t->has_candidates()) {
+ m_interpreter.execute(t);
+ t->reset_candidates();
+ }
}
- m_to_match.reset();
if (!m_new_patterns.empty()) {
match_new_patterns();
m_new_patterns.reset();
diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp
index 582911222..bf44b5dd2 100644
--- a/src/sat/smt/q_mbi.cpp
+++ b/src/sat/smt/q_mbi.cpp
@@ -114,6 +114,8 @@ namespace q {
args.push_back(replace_model_value(arg));
return expr_ref(m.mk_app(to_app(e)->get_decl(), args), m);
}
+ if (m.is_model_value(e))
+ return expr_ref(m.mk_model_value(0, e->get_sort()), m);
return expr_ref(e, m);
}
@@ -144,7 +146,7 @@ namespace q {
return l_undef;
if (m.is_false(qb->mbody))
return l_true;
- if (quick_check(q, *qb))
+ if (quick_check(q, q_flat, *qb))
return l_false;
m_generation_bound = 0;
@@ -375,6 +377,7 @@ namespace q {
m_model->reset_eval_cache();
for (app* v : qb.vars)
m_model->register_decl(v->get_decl(), mdl(v));
+ ctx.model_updated(m_model);
if (qb.var_args.empty())
return;
var_subst subst(m);
@@ -414,7 +417,16 @@ namespace q {
expr_ref value = (*m_model)(term);
expr* s = m_model_fixer.invert_app(term, value);
rep.insert(term, s);
- eqs.push_back(m.mk_eq(term, s));
+ expr_ref eq(m.mk_eq(term, s), m);
+ if (m_model->is_false(eq)) {
+ IF_VERBOSE(0,
+ verbose_stream() << mk_pp(s, m) << " := " << (*m_model)(s) << "\n";
+ verbose_stream() << mk_pp(term, m) << " := " << (*m_model)(term) << "\n";
+ verbose_stream() << value << " -> " << (*m_model)(ctx.values2root()[value]->get_expr()) << "\n";
+ verbose_stream() << (*m_model)(s) << " -> " << (*m_model)(ctx.values2root()[(*m_model)(s)]->get_expr()) << "\n";
+ verbose_stream() << *m_model << "\n";);
+ }
+ eqs.push_back(eq);
}
rep(fmls);
fmls.append(eqs);
@@ -459,18 +471,20 @@ namespace q {
}
}
- bool mbqi::quick_check(quantifier* q, q_body& qb) {
+ bool mbqi::quick_check(quantifier* q, quantifier* q_flat, q_body& qb) {
unsigned_vector offsets;
if (!first_offset(offsets, qb.vars))
return false;
var_subst subst(m);
+ expr_ref body(m);
unsigned max_rounds = m_max_quick_check_rounds;
unsigned num_bindings = 0;
expr_ref_vector binding(m);
+
for (unsigned i = 0; i < max_rounds && num_bindings < m_max_cex; ++i) {
set_binding(offsets, qb.vars, binding);
if (m_model->is_true(qb.vbody)) {
- expr_ref body = subst(q->get_expr(), binding);
+ body = subst(q_flat->get_expr(), binding);
if (is_forall(q))
body = ::mk_not(m, body);
add_instantiation(q, body);
diff --git a/src/sat/smt/q_mbi.h b/src/sat/smt/q_mbi.h
index 5cab386ae..174462ca4 100644
--- a/src/sat/smt/q_mbi.h
+++ b/src/sat/smt/q_mbi.h
@@ -96,7 +96,7 @@ namespace q {
bool check_forall_default(quantifier* q, q_body& qb, model& mdl);
bool check_forall_subst(quantifier* q, q_body& qb, model& mdl);
- bool quick_check(quantifier* q, q_body& qb);
+ bool quick_check(quantifier* q, quantifier* q_flat, q_body& qb);
bool next_offset(unsigned_vector& offsets, app_ref_vector const& vars);
bool first_offset(unsigned_vector& offsets, app_ref_vector const& vars);
bool next_offset(unsigned_vector& offsets, app_ref_vector const& vars, unsigned i, unsigned start);
diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp
index 512a21179..86c502932 100644
--- a/src/sat/smt/q_model_fixer.cpp
+++ b/src/sat/smt/q_model_fixer.cpp
@@ -218,13 +218,14 @@ namespace q {
expr* model_fixer::invert_app(app* t, expr* value) {
euf::enode* r = nullptr;
+ auto& v2r = ctx.values2root();
TRACE("q",
- tout << "invert-app " << mk_pp(t, m) << " = " << mk_pp(value, m) << "\n";
- if (ctx.values2root().find(value, r))
+ tout << "invert-app " << mk_pp(t, m) << " = " << mk_pp(value, m) << "\n";
+ if (v2r.find(value, r))
tout << "inverse " << mk_pp(r->get_expr(), m) << "\n";
- ctx.display(tout);
+ ctx.display(tout);
);
- if (ctx.values2root().find(value, r))
+ if (v2r.find(value, r))
return r->get_expr();
return value;
}
diff --git a/src/sat/smt/q_queue.cpp b/src/sat/smt/q_queue.cpp
index add7dbc41..247451fb4 100644
--- a/src/sat/smt/q_queue.cpp
+++ b/src/sat/smt/q_queue.cpp
@@ -145,7 +145,8 @@ namespace q {
ent.m_instantiated = true;
unsigned gen = get_new_gen(f, ent.m_cost);
- if (em.propagate(f.nodes(), gen, *f.c))
+ bool new_propagation = false;
+ if (em.propagate(true, f.nodes(), gen, *f.c, new_propagation))
return;
auto* ebindings = m_subst(q, num_bindings);
diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp
index 26d170fb8..eebb4a721 100644
--- a/src/sat/smt/q_solver.cpp
+++ b/src/sat/smt/q_solver.cpp
@@ -41,14 +41,31 @@ namespace q {
quantifier* q = to_quantifier(e);
auto const& exp = expand(q);
- if (exp.size() > 1) {
- for (expr* e : exp)
- add_clause(~l, ctx.internalize(e, l.sign(), false, false));
+ if (exp.size() > 1 && is_forall(q)) {
+ for (expr* e : exp) {
+ sat::literal lit = ctx.internalize(e, l.sign(), false, false);
+ add_clause(~l, lit);
+ if (ctx.relevancy_enabled())
+ ctx.add_root(~l, lit);
+ }
+ return;
+ }
+ if (exp.size() > 1 && is_exists(q)) {
+ sat::literal_vector lits;
+ lits.push_back(~l);
+ for (expr* e : exp)
+ lits.push_back(ctx.internalize(e, l.sign(), false, false));
+ add_clause(lits);
+ if (ctx.relevancy_enabled())
+ ctx.add_root(lits);
return;
}
- if (l.sign() == is_forall(e))
- add_clause(~l, skolemize(q));
+ if (l.sign() == is_forall(e)) {
+ sat::literal lit = skolemize(q);
+ add_clause(~l, lit);
+ ctx.add_root(~l, lit);
+ }
else {
ctx.push_vec(m_universal, l);
if (ctx.get_config().m_ematching)
@@ -167,9 +184,14 @@ namespace q {
return q_flat;
proof_ref pr(m);
expr_ref new_q(m);
- pull_quant pull(m);
- pull(q, new_q, pr);
- SASSERT(is_well_sorted(m, new_q));
+ if (is_forall(q)) {
+ pull_quant pull(m);
+ pull(q, new_q, pr);
+ SASSERT(is_well_sorted(m, new_q));
+ }
+ else {
+ new_q = q;
+ }
q_flat = to_quantifier(new_q);
m.inc_ref(q_flat);
m.inc_ref(q);
diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h
index 9b0301775..426104c87 100644
--- a/src/sat/smt/q_solver.h
+++ b/src/sat/smt/q_solver.h
@@ -74,7 +74,7 @@ namespace q {
euf::th_solver* clone(euf::solver& ctx) override;
bool unit_propagate() override;
sat::literal internalize(expr* e, bool sign, bool root, bool learned) override;
- void internalize(expr* e, bool redundant) override { UNREACHABLE(); }
+ void internalize(expr* e, bool redundant) override { internalize(e, false, false, redundant); }
euf::theory_var mk_var(euf::enode* n) override;
void init_search() override;
void finalize_model(model& mdl) override;
diff --git a/src/sat/smt/recfun_solver.cpp b/src/sat/smt/recfun_solver.cpp
index 264399e7d..c6080a2d4 100644
--- a/src/sat/smt/recfun_solver.cpp
+++ b/src/sat/smt/recfun_solver.cpp
@@ -328,5 +328,17 @@ namespace recfun {
}
return found;
}
+
+ bool solver::add_dep(euf::enode* n, top_sort& dep) {
+ if (n->num_args() == 0)
+ dep.insert(n, nullptr);
+ for (auto* k : euf::enode_args(n))
+ dep.add(n, k);
+ return true;
+ }
+
+ void solver::add_value(euf::enode* n, model& mdl, expr_ref_vector& values) {
+ values.set(n->get_root_id(), n->get_root()->get_expr());
+ }
}
diff --git a/src/sat/smt/recfun_solver.h b/src/sat/smt/recfun_solver.h
index cfdf6fe63..b783ed0f0 100644
--- a/src/sat/smt/recfun_solver.h
+++ b/src/sat/smt/recfun_solver.h
@@ -103,6 +103,8 @@ namespace recfun {
bool unit_propagate() override;
sat::literal internalize(expr* e, bool sign, bool root, bool learned) override;
void internalize(expr* e, bool redundant) override;
+ bool add_dep(euf::enode* n, top_sort& dep) override;
+ void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override;
bool is_shared(euf::theory_var v) const override { return true; }
void init_search() override {}
bool should_research(sat::literal_vector const& core) override;
diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp
index 7a48f8809..b392254a1 100644
--- a/src/sat/smt/sat_dual_solver.cpp
+++ b/src/sat/smt/sat_dual_solver.cpp
@@ -101,6 +101,17 @@ namespace sat {
m_solver.mk_clause(sz, m_lits.data(), status::input());
}
+ void dual_solver::add_assumptions(solver const& s) {
+ m_lits.reset();
+ for (bool_var v : m_tracked_vars)
+ m_lits.push_back(literal(v, l_false == s.value(m_var2ext[v])));
+ for (auto lit : m_units) {
+ bool_var w = m_ext2var.get(lit.var(), null_bool_var);
+ if (w != null_bool_var)
+ m_lits.push_back(ext2lit(lit));
+ }
+ }
+
bool dual_solver::operator()(solver const& s) {
m_core.reset();
m_core.append(m_units);
@@ -108,9 +119,7 @@ namespace sat {
return true;
m_solver.user_push();
m_solver.add_clause(m_roots.size(), m_roots.data(), status::input());
- m_lits.reset();
- for (bool_var v : m_tracked_vars)
- m_lits.push_back(literal(v, l_false == s.value(m_var2ext[v])));
+ add_assumptions(s);
lbool is_sat = m_solver.check(m_lits.size(), m_lits.data());
if (is_sat == l_false)
for (literal lit : m_solver.get_core())
diff --git a/src/sat/smt/sat_dual_solver.h b/src/sat/smt/sat_dual_solver.h
index 4e9b59fec..2b040128c 100644
--- a/src/sat/smt/sat_dual_solver.h
+++ b/src/sat/smt/sat_dual_solver.h
@@ -42,6 +42,8 @@ namespace sat {
literal ext2lit(literal lit);
literal lit2ext(literal lit);
+ void add_assumptions(solver const& s);
+
std::ostream& display(solver const& s, std::ostream& out) const;
public:
diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp
index c08944bee..925dac7f8 100644
--- a/src/sat/tactic/goal2sat.cpp
+++ b/src/sat/tactic/goal2sat.cpp
@@ -137,6 +137,10 @@ struct goal2sat::imp : public sat::sat_internalizer {
if (relevancy_enabled())
ensure_euf()->add_root(n, lits);
}
+
+ void add_dual_root(sat::literal lit) {
+ add_dual_root(1, &lit);
+ }
void mk_clause(sat::literal l) {
mk_clause(1, &l);
@@ -199,6 +203,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
// create fake variable to represent true;
m_true = sat::literal(add_var(false, m.mk_true()), false);
mk_clause(m_true); // v is true
+ add_dual_root(1, &m_true);
}
return m_true;
}
@@ -223,6 +228,8 @@ struct goal2sat::imp : public sat::sat_internalizer {
if (!m_expr2var_replay || !m_expr2var_replay->find(t, v))
v = add_var(true, t);
m_map.insert(t, v);
+ if (relevancy_enabled() && (m.is_true(t) || m.is_false(t)))
+ add_dual_root(sat::literal(v, m.is_false(t)));
return v;
}
@@ -737,7 +744,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
};
void process(expr* n, bool is_root, bool redundant) {
- TRACE("goal2sat", tout << "process-begin " << mk_bounded_pp(n, m, 3)
+ TRACE("goal2sat", tout << "process-begin " << mk_bounded_pp(n, m, 2)
<< " root: " << is_root
<< " result-stack: " << m_result_stack.size()
<< " frame-stack: " << m_frame_stack.size() << "\n";);
@@ -777,7 +784,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
m_frame_stack[fsz - 1].m_idx++;
if (!visit(arg, false, false))
goto loop;
- TRACE("goal2sat_bug", tout << "visit " << mk_bounded_pp(t, m, 2) << " result stack: " << m_result_stack.size() << "\n";);
+ TRACE("goal2sat_bug", tout << "visit " << mk_bounded_pp(arg, m, 2) << " result stack: " << m_result_stack.size() << "\n";);
}
TRACE("goal2sat_bug", tout << "converting\n";
tout << mk_bounded_pp(t, m, 2) << " root: " << root << " sign: " << sign << "\n";
diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp
index 4c511fa98..4d7b23166 100644
--- a/src/sat/tactic/sat_tactic.cpp
+++ b/src/sat/tactic/sat_tactic.cpp
@@ -56,6 +56,12 @@ class sat_tactic : public tactic {
for (func_decl* f : funs)
tout << mk_ismt2_pp(f, m) << "\n";
);
+
+ expr_ref_vector fmls_to_validate(m);
+ if (gparams::get_ref().get_bool("model_validate", false))
+ for (unsigned i = 0; i < g->size(); ++i)
+ fmls_to_validate.push_back(g->form(i));
+
g->reset();
g->m().compact_memory();
@@ -65,7 +71,8 @@ class sat_tactic : public tactic {
dep2assumptions(dep2asm, assumptions);
lbool r = m_solver->check(assumptions.size(), assumptions.data());
TRACE("sat", tout << "result of checking: " << r << " ";
- if (r == l_undef) tout << m_solver->get_reason_unknown(); tout << "\n";);
+ if (r == l_undef) tout << m_solver->get_reason_unknown(); tout << "\n";
+ if (m_goal2sat.has_interpreted_funs()) tout << "has interpreted\n";);
if (r == l_false) {
expr_dependency * lcore = nullptr;
if (produce_core) {
@@ -106,6 +113,10 @@ class sat_tactic : public tactic {
break;
}
}
+ for (auto* f : fmls_to_validate)
+ if (md->is_false(f))
+ IF_VERBOSE(0, verbose_stream() << "failed to validate: " << mk_pp(f, m) << "\n";);
+
m_goal2sat.update_model(md);
TRACE("sat_tactic", model_v2_pp(tout, *md););
g->add(model2model_converter(md.get()));
diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp
index 25fe5c43d..f8d99f398 100644
--- a/src/smt/mam.cpp
+++ b/src/smt/mam.cpp
@@ -1661,6 +1661,8 @@ namespace {
if (m_incompatible.empty()) {
// sequence starting at head is fully compatible
+ if (!curr)
+ return;
SASSERT(curr != 0);
SASSERT(curr->m_opcode == CHOOSE);
choose * first_child = static_cast(curr);
diff --git a/src/smt/seq_eq_solver.cpp b/src/smt/seq_eq_solver.cpp
index bd346ab4a..a8743d21c 100644
--- a/src/smt/seq_eq_solver.cpp
+++ b/src/smt/seq_eq_solver.cpp
@@ -1113,11 +1113,14 @@ bool theory_seq::is_unit_eq(expr_ref_vector const& ls, expr_ref_vector const& rs
struct remove_obj_pair_map : public trail {
+ ast_manager& m;
obj_pair_hashtable & m_map;
expr* a, *b;
- remove_obj_pair_map(obj_pair_hashtable & map, expr* a, expr* b):
- m_map(map), a(a), b(b) {}
+ remove_obj_pair_map(ast_manager& m, obj_pair_hashtable & map, expr* a, expr* b):
+ m(m), m_map(map), a(a), b(b) {}
void undo() override {
+ m.dec_ref(a);
+ m.dec_ref(b);
m_map.erase(std::make_pair(a, b));
}
};
@@ -1138,8 +1141,10 @@ bool theory_seq::solve_nth_eq(expr_ref_vector const& ls, expr_ref_vector const&
expr_ref rhs = mk_concat(rs.size(), rs.data(), ls[0]->get_sort());
if (m_nth_eq2_cache.contains(std::make_pair(rhs, ls[0])))
return false;
+ m.inc_ref(rhs);
+ m.inc_ref(ls[0]);
m_nth_eq2_cache.insert(std::make_pair(rhs, ls[0]));
- ctx.push_trail(remove_obj_pair_map(m_nth_eq2_cache, rhs, ls[0]));
+ ctx.push_trail(remove_obj_pair_map(m, m_nth_eq2_cache, rhs, ls[0]));
ls1.push_back(s);
if (!idx_is_zero) rs1.push_back(m_sk.mk_pre(s, idx));
rs1.push_back(m_util.str.mk_unit(rhs));
diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp
index 2c08ba860..ad1dda4b2 100644
--- a/src/smt/smt_context.cpp
+++ b/src/smt/smt_context.cpp
@@ -4582,31 +4582,8 @@ namespace smt {
}
void context::add_rec_funs_to_model() {
- if (!m_model) return;
- recfun::util u(m);
- func_decl_ref_vector recfuns = u.get_rec_funs();
- for (func_decl* f : recfuns) {
- auto& def = u.get_def(f);
- expr* rhs = def.get_rhs();
- if (!rhs) continue;
- if (f->get_arity() == 0) {
- m_model->register_decl(f, rhs);
- continue;
- }
-
- func_interp* fi = alloc(func_interp, m, f->get_arity());
- // reverse argument order so that variable 0 starts at the beginning.
- expr_ref_vector subst(m);
- for (unsigned i = 0; i < f->get_arity(); ++i) {
- subst.push_back(m.mk_var(i, f->get_domain(i)));
- }
- var_subst sub(m, true);
- expr_ref bodyr = sub(rhs, subst.size(), subst.data());
-
- fi->set_else(bodyr);
- m_model->register_decl(f, fi);
- }
- TRACE("model", tout << *m_model << "\n";);
+ if (m_model)
+ m_model->add_rec_funs();
}
};
diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp
index 7df758e18..ed663fbea 100644
--- a/src/smt/smt_model_finder.cpp
+++ b/src/smt/smt_model_finder.cpp
@@ -808,7 +808,6 @@ namespace smt {
if (t_val && !m.is_unique_value(t_val))
for (expr* v : values)
found |= m.are_equal(v, t_val);
-
if (t_val && !found && !already_found.contains(t_val)) {
values.push_back(t_val);
already_found.insert(t_val);
@@ -1113,9 +1112,14 @@ namespace smt {
mk_inverses();
complete_partial_funcs(partial_funcs);
TRACE("model_finder", tout << "after auf_solver fixing the model\n";
- display_nodes(tout);
- tout << "NEW MODEL:\n";
- model_pp(tout, *m_model););
+ display_nodes(tout);
+ tout << "NEW MODEL:\n";
+ model_pp(tout, *m_model););
+ }
+
+ bool is_default_representative(expr* t) {
+ app* tt = nullptr;
+ return t && m_sort2k.find(t->get_sort(), tt) && (tt == t);
}
};
@@ -1185,15 +1189,15 @@ namespace smt {
node* n1 = s.get_A_f_i(m_f, m_arg_i);
node* n2 = s.get_uvar(q, m_var_j);
CTRACE("model_finder", n1->get_sort() != n2->get_sort(),
- tout << "sort bug:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << mk_ismt2_pp(q, m) << "\n";
- tout << "decl(0): " << q->get_decl_name(0) << "\n";
- tout << "f: " << m_f->get_name() << " i: " << m_arg_i << "\n";
- tout << "v: " << m_var_j << "\n";
- n1->get_root()->display(tout, m);
- n2->get_root()->display(tout, m);
- tout << "f signature: ";
- for (unsigned i = 0; i < m_f->get_arity(); i++) tout << mk_pp(m_f->get_domain(i), m) << " ";
- tout << "-> " << mk_pp(m_f->get_range(), m) << "\n";
+ tout << "sort bug:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << mk_ismt2_pp(q, m) << "\n";
+ tout << "decl(0): " << q->get_decl_name(0) << "\n";
+ tout << "f: " << m_f->get_name() << " i: " << m_arg_i << "\n";
+ tout << "v: " << m_var_j << "\n";
+ n1->get_root()->display(tout, m);
+ n2->get_root()->display(tout, m);
+ tout << "f signature: ";
+ for (unsigned i = 0; i < m_f->get_arity(); i++) tout << mk_pp(m_f->get_domain(i), m) << " ";
+ tout << "-> " << mk_pp(m_f->get_range(), m) << "\n";
);
n1->merge(n2);
@@ -2511,6 +2515,8 @@ namespace smt {
if (s == nullptr)
return nullptr;
expr* t = s->get_inv(val);
+ if (m_auf_solver->is_default_representative(t))
+ return val;
if (t != nullptr) {
generation = s->get_generation(t);
}
diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp
index 316a36227..9422c2963 100644
--- a/src/smt/smt_model_generator.cpp
+++ b/src/smt/smt_model_generator.cpp
@@ -293,6 +293,7 @@ namespace smt {
obj_map root2proc;
ptr_vector roots;
ptr_vector procs;
+ scoped_reset _scoped_reset(*this, procs);
svector sources;
buffer dependencies;
expr_ref_vector dependency_values(m);
@@ -315,7 +316,6 @@ namespace smt {
m_context->display(tout);
);
- scoped_reset _scoped_reset(*this, procs);
for (source const& curr : sources) {
if (curr.is_fresh_value()) {
diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h
index 4978797a6..d9a43ddea 100644
--- a/src/smt/smt_quantifier.h
+++ b/src/smt/smt_quantifier.h
@@ -106,7 +106,6 @@ namespace smt {
class quantifier_manager_plugin {
public:
- quantifier_manager_plugin() {}
virtual ~quantifier_manager_plugin() {}
virtual void set_manager(quantifier_manager & qm) = 0;
diff --git a/src/smt/smt_relevancy.h b/src/smt/smt_relevancy.h
index 29032e915..53bf4807d 100644
--- a/src/smt/smt_relevancy.h
+++ b/src/smt/smt_relevancy.h
@@ -29,7 +29,6 @@ namespace smt {
void mark_as_relevant(relevancy_propagator & rp, expr * n);
void mark_args_as_relevant(relevancy_propagator & rp, app * n);
public:
- relevancy_eh() {}
virtual ~relevancy_eh() {}
/**
\brief This method is invoked when n is marked as relevant.
@@ -49,7 +48,6 @@ namespace smt {
expr * m_target;
public:
simple_relevancy_eh(expr * t):m_target(t) {}
- ~simple_relevancy_eh() override {}
void operator()(relevancy_propagator & rp) override;
};
@@ -62,7 +60,6 @@ namespace smt {
expr * m_target;
public:
pair_relevancy_eh(expr * s1, expr * s2, expr * t):m_source1(s1), m_source2(s2), m_target(t) {}
- ~pair_relevancy_eh() override {}
void operator()(relevancy_propagator & rp) override;
};
diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h
index e5bb2668d..19b0e2f6d 100644
--- a/src/smt/theory_array_full.h
+++ b/src/smt/theory_array_full.h
@@ -29,7 +29,6 @@ namespace smt {
ptr_vector m_consts;
ptr_vector m_as_arrays;
ptr_vector m_parent_maps;
- var_data_full() {}
};
ptr_vector m_var_data_full;
diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h
index 285c03b35..99e70bd74 100644
--- a/src/smt/theory_diff_logic.h
+++ b/src/smt/theory_diff_logic.h
@@ -77,7 +77,6 @@ namespace smt {
m_pos(pos),
m_neg(neg) {
}
- ~atom() {}
bool_var get_bool_var() const { return m_bvar; }
bool is_true() const { return m_true; }
void assign_eh(bool is_true) { m_true = is_true; }
@@ -383,24 +382,21 @@ namespace smt {
static const bool m_int_theory = true;
typedef rational numeral;
typedef rational fin_numeral;
- numeral m_epsilon;
- idl_ext() : m_epsilon(1) {}
+ numeral m_epsilon { 1 };
};
struct sidl_ext {
static const bool m_int_theory = true;
typedef s_integer numeral;
typedef s_integer fin_numeral;
- numeral m_epsilon;
- sidl_ext() : m_epsilon(1) {}
+ numeral m_epsilon { 1 };
};
struct rdl_ext {
static const bool m_int_theory = false;
typedef inf_int_rational numeral;
typedef rational fin_numeral;
- numeral m_epsilon;
- rdl_ext() : m_epsilon(rational(), true) {}
+ numeral m_epsilon { rational(), true };
};
//
diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp
index b76bb2fbf..1187ead7a 100644
--- a/src/smt/theory_lra.cpp
+++ b/src/smt/theory_lra.cpp
@@ -1541,8 +1541,8 @@ public:
switch (is_sat) {
case l_true:
- TRACE("arith", /*display(tout);*/
- ctx().display(tout);
+ TRACE("arith", display(tout);
+ /* ctx().display(tout);*/
);
switch (check_lia()) {
diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h
index 2006e013b..99344eb31 100644
--- a/src/smt/theory_utvpi.h
+++ b/src/smt/theory_utvpi.h
@@ -77,7 +77,6 @@ namespace smt {
atom(bool_var bv, int pos, int neg) :
m_bvar(bv), m_true(false),
m_pos(pos), m_neg(neg) {}
- ~atom() {}
bool_var get_bool_var() const { return m_bvar; }
void assign_eh(bool is_true) { m_true = is_true; }
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
diff --git a/src/solver/smt_logics.h b/src/solver/smt_logics.h
index 3e6dd9098..80bebabcc 100644
--- a/src/solver/smt_logics.h
+++ b/src/solver/smt_logics.h
@@ -20,7 +20,6 @@ Revision History:
class smt_logics {
public:
- smt_logics() {}
static bool supported_logic(symbol const & s);
static bool logic_has_reals_only(symbol const& l);
static bool logic_is_all(symbol const& s) { return s == "ALL"; }
@@ -36,5 +35,3 @@ public:
static bool logic_has_fd(symbol const& s) { return s == "QF_FD"; }
static bool logic_has_datatype(symbol const& s);
};
-
-
diff --git a/src/tactic/arith/linear_equation.h b/src/tactic/arith/linear_equation.h
index b3d43ab5e..5220a1e46 100644
--- a/src/tactic/arith/linear_equation.h
+++ b/src/tactic/arith/linear_equation.h
@@ -68,7 +68,6 @@ private:
public:
linear_equation_manager(numeral_manager & _m, small_object_allocator & a):m_allocator(a), m(_m), m_int_buffer(m), m_val_buffer(m) {}
- ~linear_equation_manager() {}
linear_equation * mk(unsigned sz, mpq * as, var * xs, bool normalized = false);
linear_equation * mk(unsigned sz, mpz * as, var * xs, bool normalized = false);
diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp
index 8a8dc9520..179bd6473 100644
--- a/src/tactic/arith/probe_arith.cpp
+++ b/src/tactic/arith/probe_arith.cpp
@@ -496,6 +496,8 @@ struct is_non_nira_functor {
throw_found(n);
if (m_linear && u.is_numeral(n->get_arg(1), r) && r.is_zero())
throw_found(n);
+ if (m_linear && u.is_numeral(n->get_arg(1), r) && !r.is_zero())
+ return;
if (!is_ground(n->get_arg(0)) || !is_ground(n->get_arg(1)))
throw_found(n);
return;
diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp
index bbc8aa007..dc193f9a8 100644
--- a/src/tactic/arith/recover_01_tactic.cpp
+++ b/src/tactic/arith/recover_01_tactic.cpp
@@ -21,7 +21,32 @@ Abstract:
q with y2=1
where y1 and y2 are fresh 01 variables
- The clauses are also removed.
+
+ Issue #5316:
+ It is in general unsound to remove clauses.
+ Example:
+
+ v or x = 0
+ ~v or x = 0
+ v or ~x = 0
+ ~v or ~x = 0
+
+ The function introduces the fresh variable 0-1 y for v.
+ The first two clauses produce the replacement x := 0*y
+ and substitution (x = 0) |-> y = 1.
+
+ After substitution:
+ y = 1 or ~(y = 1)
+ ~(y = 1) or ~(y = 1)
+
+ By retaining clauses that introduced the replacement
+ the claim is that we ensure soundness. The solution ~(y = 1)
+ is validated against the original clauses
+ v or x = 0
+ ~v or x = 0
+ that are expanded into
+ y = 1 or (y = 1)
+ ~(y = 1) or (y = 1)
Author:
@@ -37,6 +62,7 @@ Revision History:
#include "ast/expr_substitution.h"
#include "util/dec_ref_util.h"
#include "ast/ast_smt2_pp.h"
+#include "ast/ast_pp.h"
class recover_01_tactic : public tactic {
struct imp {
@@ -73,9 +99,7 @@ class recover_01_tactic : public tactic {
app * cls = to_app(c);
if (cls->get_num_args() <= 1 || cls->get_num_args() >= m_cls_max_size)
return false;
- unsigned sz = cls->get_num_args();
- for (unsigned i = 0; i < sz; i++) {
- expr * lit = cls->get_arg(i);
+ for (expr* lit : *cls) {
expr * lhs, * rhs, * arg;
if (is_uninterp_const(lit)) {
// positive literal
@@ -117,14 +141,10 @@ class recover_01_tactic : public tactic {
obj_map bool2int;
app * find_zero_cls(func_decl * x, ptr_vector & clauses) {
- ptr_vector::iterator it = clauses.begin();
- ptr_vector::iterator end = clauses.end();
- for (; it != end; ++it) {
- app * cls = *it;
- unsigned num = cls->get_num_args();
- for (unsigned i = 0; i < num; i++) {
+ for (app * cls : clauses) {
+ for (expr* arg : *cls) {
expr * lhs, * rhs;
- if (m.is_eq(cls->get_arg(i), lhs, rhs)) {
+ if (m.is_eq(arg, lhs, rhs)) {
if (is_uninterp_const(lhs) && m_util.is_zero(rhs))
return cls;
if (is_uninterp_const(rhs) && m_util.is_zero(lhs))
@@ -231,10 +251,7 @@ class recover_01_tactic : public tactic {
found.resize(expected_num_clauses, false);
idx2coeff.resize(expected_num_clauses);
- ptr_vector::iterator it = clauses.begin();
- ptr_vector::iterator end = clauses.end();
- for (; it != end; ++it) {
- app * cls = *it;
+ for (app * cls : clauses) {
unsigned idx; rational k;
if (!find_coeff(cls, zero_cls, idx, k))
return false;
@@ -281,8 +298,8 @@ class recover_01_tactic : public tactic {
if (def_args.size() == 1)
x_def = def_args[0];
else
- x_def = m_util.mk_add(def_args.size(), def_args.data());
-
+ x_def = m_util.mk_add(def_args);
+
TRACE("recover_01", tout << x->get_name() << " --> " << mk_ismt2_pp(x_def, m) << "\n";);
subst->insert(m.mk_const(x), x_def);
if (m_produce_models) {
@@ -309,12 +326,9 @@ class recover_01_tactic : public tactic {
for (unsigned i = 0; i < g->size(); i++) {
expr * f = g->form(i);
- if (save_clause(f)) {
+ if (save_clause(f))
saved = true;
- }
- else {
- new_goal->assert_expr(f);
- }
+ new_goal->assert_expr(f);
}
if (!saved) {
diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h
index 3b5005347..541d50838 100644
--- a/src/tactic/core/dom_simplify_tactic.h
+++ b/src/tactic/core/dom_simplify_tactic.h
@@ -64,8 +64,6 @@ public:
class dom_simplifier {
public:
- dom_simplifier() {}
-
virtual ~dom_simplifier() {}
/**
\brief assert_expr performs an implicit push
diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp
index f5756bfd4..4df4d1fc4 100644
--- a/src/tactic/core/elim_uncnstr_tactic.cpp
+++ b/src/tactic/core/elim_uncnstr_tactic.cpp
@@ -21,6 +21,7 @@ Notes:
#include "ast/rewriter/rewriter_def.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
+#include "ast/recfun_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "tactic/core/collect_occs.h"
@@ -784,7 +785,7 @@ class elim_uncnstr_tactic : public tactic {
m_vars.reset();
collect_occs p;
p(*g, m_vars);
- if (m_vars.empty()) {
+ if (m_vars.empty() || recfun::util(m()).has_defs()) {
result.push_back(g.get());
// did not increase depth since it didn't do anything.
return;
diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp
index 6a844a594..eef9ae77a 100644
--- a/src/tactic/smtlogics/quant_tactics.cpp
+++ b/src/tactic/smtlogics/quant_tactics.cpp
@@ -107,7 +107,7 @@ tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) {
mk_qe_lite_tactic(m, p),
cond(mk_has_quantifier_probe(),
cond(mk_is_lira_probe(),
- mk_qsat_tactic(m, p),
+ or_else(mk_qsat_tactic(m, p), mk_smt_tactic(m)),
mk_smt_tactic(m)),
mk_smt_tactic(m)));
st->updt_params(p);
diff --git a/src/util/approx_set.h b/src/util/approx_set.h
index bce67f692..7355437b9 100644
--- a/src/util/approx_set.h
+++ b/src/util/approx_set.h
@@ -164,7 +164,7 @@ typedef approx_set_tpl u_approx_set;
class approx_set : public u_approx_set {
public:
- approx_set():u_approx_set() {}
+ approx_set() = default;
approx_set(unsigned e):u_approx_set(e) {}
class iterator {
diff --git a/src/util/basic_interval.h b/src/util/basic_interval.h
index 1c15317e0..ca5868b88 100644
--- a/src/util/basic_interval.h
+++ b/src/util/basic_interval.h
@@ -33,7 +33,6 @@ public:
bound m_lower;
bound m_upper;
public:
- interval() {}
bound const & lower() const { return m_lower; }
bound const & upper() const { return m_upper; }
bound & lower() { return m_lower; }
diff --git a/src/util/buffer.h b/src/util/buffer.h
index e1721f94e..f40914638 100644
--- a/src/util/buffer.h
+++ b/src/util/buffer.h
@@ -27,11 +27,11 @@ Revision History:
template
class buffer {
protected:
- T * m_buffer;
- unsigned m_pos;
- unsigned m_capacity;
- char m_initial_buffer[INITIAL_SIZE * sizeof(T)];
-
+ T * m_buffer = reinterpret_cast(m_initial_buffer);
+ unsigned m_pos = 0;
+ unsigned m_capacity = INITIAL_SIZE;
+ typename std::aligned_storage::type m_initial_buffer[INITIAL_SIZE];
+
void free_memory() {
if (m_buffer != reinterpret_cast(m_initial_buffer)) {
dealloc_svect(m_buffer);
@@ -39,7 +39,7 @@ protected:
}
void expand() {
- static_assert(std::is_nothrow_move_constructible::value, "");
+ static_assert(std::is_nothrow_move_constructible::value);
unsigned new_capacity = m_capacity << 1;
T * new_buffer = reinterpret_cast(memory::allocate(sizeof(T) * new_capacity));
for (unsigned i = 0; i < m_pos; ++i) {
@@ -73,26 +73,30 @@ public:
typedef T * iterator;
typedef const T * const_iterator;
- buffer():
- m_buffer(reinterpret_cast(m_initial_buffer)),
- m_pos(0),
- m_capacity(INITIAL_SIZE) {
- }
+ buffer() = default;
- buffer(const buffer & source):
- m_buffer(reinterpret_cast(m_initial_buffer)),
- m_pos(0),
- m_capacity(INITIAL_SIZE) {
- unsigned sz = source.size();
- for(unsigned i = 0; i < sz; i++) {
+ buffer(const buffer & source) {
+ for (unsigned i = 0, sz = source.size(); i < sz; ++i) {
push_back(source.m_buffer[i]);
}
}
-
- buffer(unsigned sz, const T & elem):
- m_buffer(reinterpret_cast(m_initial_buffer)),
- m_pos(0),
- m_capacity(INITIAL_SIZE) {
+
+ buffer(buffer && source) noexcept {
+ if (source.m_buffer == reinterpret_cast(source.m_initial_buffer)) {
+ for (unsigned i = 0, sz = source.size(); i < sz; ++i) {
+ push_back(std::move(source.m_buffer[i]));
+ }
+ } else {
+ m_buffer = source.m_buffer;
+ m_pos = source.m_pos;
+ m_capacity = source.m_capacity;
+ source.m_buffer = reinterpret_cast(source.m_initial_buffer);
+ source.m_pos = 0;
+ source.m_capacity = INITIAL_SIZE;
+ }
+ }
+
+ buffer(unsigned sz, const T & elem) {
for (unsigned i = 0; i < sz; i++) {
push_back(elem);
}
diff --git a/src/util/dictionary.h b/src/util/dictionary.h
index dab52f938..a65144b3f 100644
--- a/src/util/dictionary.h
+++ b/src/util/dictionary.h
@@ -20,8 +20,4 @@ Notes:
#include "util/symbol.h"
template
-class dictionary : public map {
-public:
- dictionary() {}
-};
-
+using dictionary = map;
diff --git a/src/util/hashtable.h b/src/util/hashtable.h
index e904abe11..cfe4d20ca 100644
--- a/src/util/hashtable.h
+++ b/src/util/hashtable.h
@@ -44,11 +44,10 @@ typedef enum { HT_FREE,
template
class default_hash_entry {
unsigned m_hash{ 0 }; //!< cached hash code
- hash_entry_state m_state;
+ hash_entry_state m_state = HT_FREE;
T m_data;
public:
typedef T data;
- default_hash_entry():m_state(HT_FREE), m_data() {}
unsigned get_hash() const { return m_hash; }
bool is_free() const { return m_state == HT_FREE; }
bool is_deleted() const { return m_state == HT_DELETED; }
@@ -67,10 +66,9 @@ public:
template
class int_hash_entry {
unsigned m_hash; //!< cached hash code
- int m_data;
+ int m_data = Free;
public:
typedef int data;
- int_hash_entry():m_data(Free) {}
unsigned get_hash() const { return m_hash; }
bool is_free() const { return m_data == Free; }
bool is_deleted() const { return m_data == Deleted; }
@@ -89,10 +87,9 @@ public:
template
class ptr_hash_entry {
unsigned m_hash; //!< cached hash code
- T * m_ptr;
+ T * m_ptr = nullptr;
public:
typedef T * data;
- ptr_hash_entry():m_ptr(nullptr) {}
unsigned get_hash() const { return m_hash; }
bool is_free() const { return m_ptr == nullptr; }
bool is_deleted() const { return m_ptr == reinterpret_cast(1); }
@@ -112,10 +109,9 @@ public:
*/
template
class ptr_addr_hash_entry : public ptr_hash_entry {
- T * m_ptr;
+ T * m_ptr = nullptr;
public:
typedef T * data;
- ptr_addr_hash_entry():m_ptr(nullptr) {}
unsigned get_hash() const { return get_ptr_hash(m_ptr); }
bool is_free() const { return m_ptr == nullptr; }
bool is_deleted() const { return m_ptr == reinterpret_cast(1); }
diff --git a/src/util/lim_vector.h b/src/util/lim_vector.h
index 1249a9657..15cc286a2 100644
--- a/src/util/lim_vector.h
+++ b/src/util/lim_vector.h
@@ -22,8 +22,6 @@ template
class lim_svector : public svector {
unsigned_vector m_lim;
public:
- lim_svector() {}
-
void push_scope() {
m_lim.push_back(this->size());
}
diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h
index 0bf67592c..64a718bd1 100644
--- a/src/util/max_cliques.h
+++ b/src/util/max_cliques.h
@@ -86,8 +86,6 @@ class max_cliques : public T {
unsigned_vector const& next(unsigned vertex) const { return m_next[vertex]; }
public:
- max_cliques() {}
-
void add_edge(unsigned src, unsigned dst) {
m_next.reserve(std::max(src, dst) + 1);
m_next.reserve(std::max(negate(src), negate(dst)) + 1);
diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp
index 7d7c3b081..c25a04dbc 100644
--- a/src/util/mpz.cpp
+++ b/src/util/mpz.cpp
@@ -48,12 +48,12 @@ Revision History:
#endif
-#if defined(_WINDOWS) && !defined(_M_ARM) && !defined(_M_ARM64)
+#if defined(__GNUC__)
+#define _trailing_zeros32(X) __builtin_ctz(X)
+#elif defined(_WINDOWS) && !defined(_M_ARM) && !defined(_M_ARM64) && !defined(__MINGW32__)
// This is needed for _tzcnt_u32 and friends.
#include
#define _trailing_zeros32(X) _tzcnt_u32(X)
-#elif defined(__GNUC__)
-#define _trailing_zeros32(X) __builtin_ctz(X)
#else
static uint32_t _trailing_zeros32(uint32_t x) {
uint32_t r = 0;
diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h
index e45bcc57b..254f5f70d 100644
--- a/src/util/obj_hashtable.h
+++ b/src/util/obj_hashtable.h
@@ -29,10 +29,9 @@ Revision History:
*/
template
class obj_hash_entry {
- T * m_ptr;
+ T * m_ptr = nullptr;
public:
typedef T * data;
- obj_hash_entry():m_ptr(nullptr) {}
unsigned get_hash() const { return m_ptr->hash(); }
bool is_free() const { return m_ptr == nullptr; }
bool is_deleted() const { return m_ptr == reinterpret_cast(1); }
@@ -82,7 +81,6 @@ public:
key_data m_data;
public:
typedef key_data data;
- obj_map_entry() {}
unsigned get_hash() const { return m_data.hash(); }
bool is_free() const { return m_data.m_key == nullptr; }
bool is_deleted() const { return m_data.m_key == reinterpret_cast(1); }
diff --git a/src/util/obj_pair_hashtable.h b/src/util/obj_pair_hashtable.h
index 03fdcc017..e9d2e9bb5 100644
--- a/src/util/obj_pair_hashtable.h
+++ b/src/util/obj_pair_hashtable.h
@@ -29,11 +29,10 @@ Revision History:
template
class obj_pair_hash_entry {
unsigned m_hash; // cached hash code
- std::pair m_data;
+ std::pair m_data { nullptr, nullptr };
public:
typedef std::pair data;
- obj_pair_hash_entry():m_data(static_cast(nullptr),static_cast(nullptr)) {}
unsigned get_hash() const { return m_hash; }
bool is_free() const { return m_data.first == 0; }
bool is_deleted() const { return m_data.first == reinterpret_cast(1); }
@@ -94,7 +93,6 @@ protected:
key_data m_data;
public:
typedef key_data data;
- entry() {}
unsigned get_hash() const { return m_data.hash(); }
bool is_free() const { return m_data.m_key1 == nullptr; }
bool is_deleted() const { return m_data.m_key1 == reinterpret_cast(1); }
diff --git a/src/util/obj_pair_set.h b/src/util/obj_pair_set.h
index 83cc00bd8..8280e2521 100644
--- a/src/util/obj_pair_set.h
+++ b/src/util/obj_pair_set.h
@@ -34,7 +34,6 @@ protected:
typedef chashtable set;
set m_set;
public:
- obj_pair_set() {}
void insert(T1 * t1, T2 * t2) { m_set.insert(obj_pair(t1, t2)); }
void insert(obj_pair const & p) { m_set.insert(p); }
bool insert_if_not_there(T1 * t1, T2 * t2) { return m_set.insert_if_not_there2(obj_pair(t1, t2)); }
diff --git a/src/util/obj_triple_hashtable.h b/src/util/obj_triple_hashtable.h
index cd1f17651..7d75084fe 100644
--- a/src/util/obj_triple_hashtable.h
+++ b/src/util/obj_triple_hashtable.h
@@ -30,11 +30,10 @@ Revision History:
template
class obj_triple_hash_entry {
unsigned m_hash; // cached hash code
- triple m_data;
+ triple m_data { nullptr, nullptr, nullptr };
public:
typedef triple data;
- obj_triple_hash_entry():m_data(0,0,0) {}
unsigned get_hash() const { return m_hash; }
bool is_free() const { return m_data.first == 0; }
bool is_deleted() const { return m_data.first == reinterpret_cast(1); }
@@ -99,7 +98,6 @@ protected:
key_data m_data;
public:
typedef key_data data;
- entry() {}
unsigned get_hash() const { return m_data.hash(); }
bool is_free() const { return m_data.m_key1 == nullptr; }
bool is_deleted() const { return m_data.m_key1 == reinterpret_cast(1); }
diff --git a/src/util/sat_literal.h b/src/util/sat_literal.h
index 1e587644e..ccfecffba 100644
--- a/src/util/sat_literal.h
+++ b/src/util/sat_literal.h
@@ -87,7 +87,7 @@ namespace sat {
};
const literal null_literal;
- struct literal_hash : obj_hash {};
+ using literal_hash = obj_hash;
inline literal to_literal(unsigned x) { literal l; l.m_val = x; return l; }
inline bool operator<(literal const & l1, literal const & l2) { return l1.m_val < l2.m_val; }
diff --git a/src/util/scoped_vector.h b/src/util/scoped_vector.h
index 8bf481944..2c6cfaa21 100644
--- a/src/util/scoped_vector.h
+++ b/src/util/scoped_vector.h
@@ -22,8 +22,8 @@ Revision History:
template
class scoped_vector {
- unsigned m_size;
- unsigned m_elems_start;
+ unsigned m_size = 0;
+ unsigned m_elems_start = 0;
unsigned_vector m_sizes;
vector m_elems;
unsigned_vector m_elems_lim;
@@ -31,8 +31,6 @@ class scoped_vector {
unsigned_vector m_src, m_dst;
unsigned_vector m_src_lim;
public:
- scoped_vector(): m_size(0), m_elems_start(0) {}
-
// m_index : External-Index -> Internal-Index
// m_index.size() = max(m_sizes)
// m_src[i] -> m_dst[i] // trail into m_index updates
@@ -183,4 +181,3 @@ private:
m_elems_start <= m_elems.size();
}
};
-
diff --git a/src/util/symbol.cpp b/src/util/symbol.cpp
index aed40b521..5f8c6ca30 100644
--- a/src/util/symbol.cpp
+++ b/src/util/symbol.cpp
@@ -23,6 +23,7 @@ Revision History:
#include "util/region.h"
#include "util/string_buffer.h"
#include
+#include
#ifndef SINGLE_THREAD
#include
#endif
@@ -35,6 +36,7 @@ const symbol symbol::null;
/**
\brief Symbol table manager. It stores the symbol strings created at runtime.
*/
+namespace {
class internal_symbol_table {
region m_region; //!< Region used to store symbol strings.
str_hashtable m_table; //!< Table of created symbol strings.
@@ -73,6 +75,22 @@ public:
return result;
}
};
+}
+
+#ifdef SINGLE_THREAD
+static std::optional g_symbol_tables;
+
+void initialize_symbols() {
+ if (!g_symbol_tables) {
+ g_symbol_tables.emplace();
+ }
+}
+
+void finalize_symbols() {
+ g_symbol_tables.reset();
+}
+
+#else
struct internal_symbol_tables {
unsigned sz;
@@ -101,11 +119,7 @@ static internal_symbol_tables* g_symbol_tables = nullptr;
void initialize_symbols() {
if (!g_symbol_tables) {
-#ifdef SINGLE_THREAD
- unsigned num_tables = 1;
-#else
unsigned num_tables = 2 * std::min((unsigned) std::thread::hardware_concurrency(), 64u);
-#endif
g_symbol_tables = alloc(internal_symbol_tables, num_tables);
}
@@ -115,6 +129,7 @@ void finalize_symbols() {
dealloc(g_symbol_tables);
g_symbol_tables = nullptr;
}
+#endif
symbol::symbol(char const * d) {
if (d == nullptr)
@@ -130,11 +145,8 @@ symbol & symbol::operator=(char const * d) {
std::string symbol::str() const {
SASSERT(!is_marked());
- if (GET_TAG(m_data) == 0) {
- if (m_data)
- return m_data;
- else
- return "";
+ if (GET_TAG(m_data) == 0) {
+ return m_data ? m_data : "";
}
else {
string_buffer<128> buffer;
diff --git a/src/util/trail.h b/src/util/trail.h
index 2ef2bdbff..969c4a746 100644
--- a/src/util/trail.h
+++ b/src/util/trail.h
@@ -26,8 +26,7 @@ Revision History:
class trail {
public:
- virtual ~trail() {
- }
+ virtual ~trail() {}
virtual void undo() = 0;
};
@@ -48,9 +47,6 @@ public:
m_value = new_value;
}
- ~value_trail() override {
- }
-
void undo() override {
m_value = m_old_value;
}
@@ -69,9 +65,6 @@ public:
m_values(values) {
}
- ~scoped_value_trail() override {
- }
-
void undo() override {
m_value = m_values.back();
m_values.pop_back();
@@ -86,9 +79,6 @@ public:
m_value(value) {
}
- ~reset_flag_trail() override {
- }
-
void undo() override {
m_value = false;
}
@@ -121,8 +111,7 @@ public:
m_vector(v),
m_old_size(v.size()) {
}
- ~restore_size_trail() override {
- }
+
void undo() override {
m_vector.shrink(m_old_size);
}
@@ -140,9 +129,6 @@ public:
m_old_value(v[idx]) {
}
- ~vector_value_trail() override {
- }
-
void undo() override {
m_vector[m_idx] = m_old_value;
}
@@ -162,9 +148,6 @@ public:
m_old_value(v[i][j]) {
}
- ~vector2_value_trail() override {
- }
-
void undo() override {
m_vector[m_i][m_j] = m_old_value;
}
@@ -177,7 +160,6 @@ class insert_obj_map : public trail {
D* m_obj;
public:
insert_obj_map(obj_map& t, D* o) : m_map(t), m_obj(o) {}
- ~insert_obj_map() override {}
void undo() override { m_map.remove(m_obj); }
};
@@ -188,7 +170,6 @@ class remove_obj_map : public trail {
R m_value;
public:
remove_obj_map(obj_map& t, D* o, R v) : m_map(t), m_obj(o), m_value(v) {}
- ~remove_obj_map() override {}
void undo() override { m_map.insert(m_obj, m_value); }
};
@@ -198,7 +179,6 @@ class insert_map : public trail {
D m_obj;
public:
insert_map(M& t, D o) : m_map(t), m_obj(o) {}
- ~insert_map() override {}
void undo() override { m_map.remove(m_obj); }
};
@@ -210,8 +190,7 @@ class insert_ref_map : public trail {
D m_obj;
public:
insert_ref_map(Mgr& m, M& t, D o) : m(m), m_map(t), m_obj(o) {}
- virtual ~insert_ref_map() {}
- virtual void undo() { m_map.remove(m_obj); m.dec_ref(m_obj); }
+ void undo() override { m_map.remove(m_obj); m.dec_ref(m_obj); }
};
template
@@ -222,8 +201,7 @@ class insert_ref2_map : public trail {
R* m_val;
public:
insert_ref2_map(Mgr& m, obj_map& t, D*o, R*r) : m(m), m_map(t), m_obj(o), m_val(r) {}
- virtual ~insert_ref2_map() {}
- virtual void undo() { m_map.remove(m_obj); m.dec_ref(m_obj); m.dec_ref(m_val); }
+ void undo() override { m_map.remove(m_obj); m.dec_ref(m_obj); m.dec_ref(m_val); }
};
@@ -250,9 +228,6 @@ public:
m_idx(idx) {
}
- ~set_vector_idx_trail() override {
- }
-
void undo() override {
m_vector[m_idx] = nullptr;
}
@@ -286,7 +261,7 @@ public:
m_value(m_vector[index].back()) {
}
- virtual void undo() {
+ void undo() override {
m_vector[m_index].push_back(m_value);
}
};
@@ -317,7 +292,7 @@ public:
m_index(index) {
}
- virtual void undo() {
+ void undo() override {
m_vector[m_index].pop_back();
}
};
@@ -351,9 +326,6 @@ public:
m_idx(idx),
m_hist(hist) {}
- ~history_trail() override {
- }
-
void undo() override {
m_dst[m_idx] = m_hist.back();
m_hist.pop_back();
@@ -382,7 +354,7 @@ public:
m_obj(obj) {
}
- virtual void undo() {
+ void undo() override {
m_obj.reset();
}
};
@@ -393,7 +365,6 @@ class insert_obj_trail : public trail {
T* m_obj;
public:
insert_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {}
- ~insert_obj_trail() override {}
void undo() override { m_table.remove(m_obj); }
};
@@ -404,8 +375,7 @@ class remove_obj_trail : public trail {
T* m_obj;
public:
remove_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {}
- virtual ~remove_obj_trail() {}
- virtual void undo() { m_table.insert(m_obj); }
+ void undo() override { m_table.insert(m_obj); }
};
@@ -425,10 +395,6 @@ class trail_stack {
unsigned_vector m_scopes;
region m_region;
public:
- trail_stack() {}
-
- ~trail_stack() {}
-
region & get_region() { return m_region; }
void reset() {
@@ -457,4 +423,3 @@ public:
m_region.pop_scope(num_scopes);
}
};
-
diff --git a/src/util/union_find.h b/src/util/union_find.h
index 664efefda..c82d25857 100644
--- a/src/util/union_find.h
+++ b/src/util/union_find.h
@@ -24,7 +24,6 @@ Revision History:
class union_find_default_ctx {
public:
typedef trail_stack _trail_stack;
- union_find_default_ctx() : m_stack() {}
void unmerge_eh(unsigned, unsigned) {}
void merge_eh(unsigned, unsigned, unsigned, unsigned) {}
@@ -51,7 +50,6 @@ class union_find {
union_find & m_owner;
public:
mk_var_trail(union_find & o):m_owner(o) {}
- ~mk_var_trail() override {}
void undo() override {
m_owner.m_find.pop_back();
m_owner.m_size.pop_back();
@@ -69,7 +67,6 @@ class union_find {
unsigned m_r1;
public:
merge_trail(union_find & o, unsigned r1):m_owner(o), m_r1(r1) {}
- ~merge_trail() override {}
void undo() override { m_owner.unmerge(m_r1); }
};
diff --git a/src/util/vector.h b/src/util/vector.h
index aa36c4972..c00a1e101 100644
--- a/src/util/vector.h
+++ b/src/util/vector.h
@@ -163,14 +163,10 @@ template
class vector {
#define SIZE_IDX -1
#define CAPACITY_IDX -2
- T * m_data;
+ T * m_data = nullptr;
void destroy_elements() {
- iterator it = begin();
- iterator e = end();
- for (; it != e; ++it) {
- it->~T();
- }
+ std::destroy_n(m_data, size());
}
void free_memory() {
@@ -178,17 +174,21 @@ class vector {
}
void expand_vector() {
+ // ensure that the data is sufficiently aligned
+ // better fail to compile than produce code that may crash
+ static_assert((sizeof(SZ) * 2) % alignof(T) == 0);
+
if (m_data == nullptr) {
SZ capacity = 2;
SZ * mem = reinterpret_cast(memory::allocate(sizeof(T) * capacity + sizeof(SZ) * 2));
- *mem = capacity;
+ *mem = capacity;
mem++;
- *mem = 0;
+ *mem = 0;
mem++;
- m_data = reinterpret_cast(mem);
+ m_data = reinterpret_cast(mem);
}
else {
- static_assert(std::is_nothrow_move_constructible::value, "");
+ static_assert(std::is_nothrow_move_constructible::value);
SASSERT(capacity() > 0);
SZ old_capacity = reinterpret_cast(m_data)[CAPACITY_IDX];
SZ old_capacity_T = sizeof(T) * old_capacity + sizeof(SZ) * 2;
@@ -203,15 +203,12 @@ class vector {
m_data = reinterpret_cast(mem + 2);
} else {
mem = (SZ*)memory::allocate(new_capacity_T);
- auto old_data = m_data;
auto old_size = size();
mem[1] = old_size;
- m_data = reinterpret_cast(mem + 2);
- for (unsigned i = 0; i < old_size; ++i) {
- new (&m_data[i]) T(std::move(old_data[i]));
- old_data[i].~T();
- }
- memory::deallocate(old_mem);
+ auto new_data = reinterpret_cast(mem + 2);
+ std::uninitialized_move_n(m_data, old_size, new_data);
+ destroy();
+ m_data = new_data;
}
*mem = new_capacity;
}
@@ -243,12 +240,9 @@ public:
typedef T * iterator;
typedef const T * const_iterator;
- vector():
- m_data(nullptr) {
- }
+ vector() = default;
vector(SZ s) {
- m_data = nullptr;
init(s);
}
@@ -271,25 +265,22 @@ public:
}
}
- vector(SZ s, T const & elem):
- m_data(nullptr) {
+ vector(SZ s, T const & elem) {
resize(s, elem);
}
- vector(vector const & source):
- m_data(nullptr) {
+ vector(vector const & source) {
if (source.m_data) {
copy_core(source);
}
SASSERT(size() == source.size());
}
- vector(vector&& other) noexcept : m_data(nullptr) {
+ vector(vector&& other) noexcept {
std::swap(m_data, other.m_data);
}
- vector(SZ s, T const * data):
- m_data(nullptr) {
+ vector(SZ s, T const * data) {
for (SZ i = 0; i < s; i++) {
push_back(data[i]);
}
@@ -321,7 +312,6 @@ public:
bool operator!=(vector const & other) const {
return !(*this == other);
}
-
vector & operator=(vector const & source) {
if (this == &source) {
diff --git a/src/util/zstring.cpp b/src/util/zstring.cpp
index d5f123533..46c9d9fce 100644
--- a/src/util/zstring.cpp
+++ b/src/util/zstring.cpp
@@ -276,16 +276,10 @@ bool operator<(const zstring& lhs, const zstring& rhs) {
for (unsigned i = 0; i < len; ++i) {
unsigned Li = lhs[i];
unsigned Ri = rhs[i];
- if (Li < Ri) {
- return true;
- }
- else if (Li > Ri) {
- return false;
- }
+ if (Li != Ri)
+ return Li < Ri;
}
// at this point, all compared characters are equal,
// so decide based on the relative lengths
return lhs.length() < rhs.length();
}
-
-
diff --git a/src/util/zstring.h b/src/util/zstring.h
index 7531390c8..a15d1b03d 100644
--- a/src/util/zstring.h
+++ b/src/util/zstring.h
@@ -16,14 +16,14 @@ Author:
--*/
#pragma once
+#include
#include
-#include "util/vector.h"
#include "util/buffer.h"
#include "util/rational.h"
class zstring {
private:
- buffer m_buffer;
+ buffer m_buffer;
bool well_formed() const;
bool uses_unicode() const;
bool is_escape_char(char const *& s, unsigned& result);
@@ -32,7 +32,7 @@ public:
static unsigned unicode_num_bits() { return 18; }
static unsigned ascii_max_char() { return 255; }
static unsigned ascii_num_bits() { return 8; }
- zstring() {}
+ zstring() = default;
zstring(char const* s);
zstring(const std::string &str) : zstring(str.c_str()) {}
zstring(rational const& r): zstring(r.to_string()) {}