mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into poly
This commit is contained in:
		
						commit
						94955e3fae
					
				
					 67 changed files with 2698 additions and 806 deletions
				
			
		|  | @ -226,7 +226,7 @@ to Z3's C API. For more information, see [MachineArithmetic/README.md](https://g | ||||||
| * Default input format is [SMTLIB2](http://smtlib.cs.uiowa.edu) | * Default input format is [SMTLIB2](http://smtlib.cs.uiowa.edu) | ||||||
| 
 | 
 | ||||||
| * Other native foreign function interfaces: | * Other native foreign function interfaces: | ||||||
| * [C++ API](https://z3prover.github.io/api/html/group__cppapi.html) | * [C++ API](https://z3prover.github.io/api/html/namespacez3.html) | ||||||
| * [.NET API](https://z3prover.github.io/api/html/namespace_microsoft_1_1_z3.html) | * [.NET API](https://z3prover.github.io/api/html/namespace_microsoft_1_1_z3.html) | ||||||
| * [Java API](https://z3prover.github.io/api/html/namespacecom_1_1microsoft_1_1z3.html) | * [Java API](https://z3prover.github.io/api/html/namespacecom_1_1microsoft_1_1z3.html) | ||||||
| * [Python API](https://z3prover.github.io/api/html/namespacez3py.html) (also available in [pydoc format](https://z3prover.github.io/api/html/z3.html)) | * [Python API](https://z3prover.github.io/api/html/namespacez3py.html) (also available in [pydoc format](https://z3prover.github.io/api/html/z3.html)) | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ | ||||||
| from mk_util import * | from mk_util import * | ||||||
| 
 | 
 | ||||||
| def init_version(): | def init_version(): | ||||||
|     set_version(4, 13, 0, 1) # express a default build version or pick up ci build version |     set_version(4, 13, 1, 0) # express a default build version or pick up ci build version | ||||||
|      |      | ||||||
| # Z3 Project definition | # Z3 Project definition | ||||||
| def init_project_def(): | def init_project_def(): | ||||||
|  |  | ||||||
|  | @ -314,6 +314,26 @@ def test_fpmath(cc): | ||||||
|         FPMATH_FLAGS="" |         FPMATH_FLAGS="" | ||||||
|         return "UNKNOWN" |         return "UNKNOWN" | ||||||
| 
 | 
 | ||||||
|  | def test_atomic_required(cc): | ||||||
|  |     t = TempFile('tstatomic.cpp') | ||||||
|  |     t.add(""" | ||||||
|  |     #include <atomic> | ||||||
|  |     std::atomic<int> x; | ||||||
|  |     std::atomic<short> y; | ||||||
|  |     std::atomic<char> z; | ||||||
|  |     std::atomic<long long> w; | ||||||
|  |     int main() { | ||||||
|  |         ++z; | ||||||
|  |         ++y; | ||||||
|  |         ++w; | ||||||
|  |         return ++x; | ||||||
|  |     } | ||||||
|  |     """) | ||||||
|  |     t.commit() | ||||||
|  |     fails_without = exec_compiler_cmd([cc, CPPFLAGS, '', 'tstatomic.cpp', LDFLAGS, '']) != 0 | ||||||
|  |     ok_with = exec_compiler_cmd([cc, CPPFLAGS, '', 'tstatomic.cpp', LDFLAGS + ' -latomic', '']) == 0 | ||||||
|  |     return fails_without and ok_with | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| def find_jni_h(path): | def find_jni_h(path): | ||||||
|     for root, dirs, files in os.walk(path): |     for root, dirs, files in os.walk(path): | ||||||
|  | @ -2600,6 +2620,9 @@ def mk_config(): | ||||||
|         CXXFLAGS = '%s -fvisibility=hidden -fvisibility-inlines-hidden -c' % CXXFLAGS |         CXXFLAGS = '%s -fvisibility=hidden -fvisibility-inlines-hidden -c' % CXXFLAGS | ||||||
|         FPMATH = test_fpmath(CXX) |         FPMATH = test_fpmath(CXX) | ||||||
|         CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) |         CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) | ||||||
|  |         atomic_required = test_atomic_required(CXX) | ||||||
|  |         if atomic_required: | ||||||
|  |             LDFLAGS  = '%s -latomic' % LDFLAGS | ||||||
|         if LOG_SYNC: |         if LOG_SYNC: | ||||||
|             CXXFLAGS = '%s -DZ3_LOG_SYNC' % CXXFLAGS |             CXXFLAGS = '%s -DZ3_LOG_SYNC' % CXXFLAGS | ||||||
|         if SINGLE_THREADED: |         if SINGLE_THREADED: | ||||||
|  | @ -2710,6 +2733,7 @@ def mk_config(): | ||||||
|             print('Prefix:         %s' % PREFIX) |             print('Prefix:         %s' % PREFIX) | ||||||
|             print('64-bit:         %s' % is64()) |             print('64-bit:         %s' % is64()) | ||||||
|             print('FP math:        %s' % FPMATH) |             print('FP math:        %s' % FPMATH) | ||||||
|  |             print('libatomic:      %s' % ('required' if atomic_required else 'not required')) | ||||||
|             print("Python pkg dir: %s" % PYTHON_PACKAGE_DIR) |             print("Python pkg dir: %s" % PYTHON_PACKAGE_DIR) | ||||||
|             if GPROF: |             if GPROF: | ||||||
|                 print('gprof:          enabled') |                 print('gprof:          enabled') | ||||||
|  |  | ||||||
|  | @ -114,10 +114,19 @@ stages: | ||||||
|     pool: |     pool: | ||||||
|       vmImage: "ubuntu-latest" |       vmImage: "ubuntu-latest" | ||||||
|     steps: |     steps: | ||||||
|     - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 |     - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz?rev=33c6e30e5ac64e6dba8f0431f2c35f1b&hash=9918A05BF47621B632C7A5C8D2BB438FB80A4480' | ||||||
|     - script: git clone https://github.com/z3prover/z3test z3test |     - script: mkdir -p /tmp/arm-toolchain/ | ||||||
|     - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2     |     - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 | ||||||
|     - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. |     - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' | ||||||
|  |     - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin' | ||||||
|  |     - script: echo $PATH | ||||||
|  |     - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc | ||||||
|  |     - script: python scripts/mk_unix_dist.py --nodotnet --nojava --arch=arm64 | ||||||
|  |     - task: CopyFiles@2 | ||||||
|  |       inputs: | ||||||
|  |         sourceFolder: dist | ||||||
|  |         contents: '*.zip' | ||||||
|  |         targetFolder: $(Build.ArtifactStagingDirectory) | ||||||
|     - task: PublishPipelineArtifact@0 |     - task: PublishPipelineArtifact@0 | ||||||
|       inputs: |       inputs: | ||||||
|         artifactName: 'UbuntuArm64' |         artifactName: 'UbuntuArm64' | ||||||
|  |  | ||||||
|  | @ -119,10 +119,19 @@ stages: | ||||||
|     pool: |     pool: | ||||||
|       vmImage: "ubuntu-latest" |       vmImage: "ubuntu-latest" | ||||||
|     steps: |     steps: | ||||||
|     - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 |      - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz?rev=33c6e30e5ac64e6dba8f0431f2c35f1b&hash=9918A05BF47621B632C7A5C8D2BB438FB80A4480' | ||||||
|     - script: git clone https://github.com/z3prover/z3test z3test |     - script: mkdir -p /tmp/arm-toolchain/ | ||||||
|     - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2     |     - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 | ||||||
|     - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. |     - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' | ||||||
|  |     - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin' | ||||||
|  |     - script: echo $PATH | ||||||
|  |     - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc | ||||||
|  |     - script: python scripts/mk_unix_dist.py --nodotnet --nojava --arch=arm64 | ||||||
|  |     - task: CopyFiles@2 | ||||||
|  |       inputs: | ||||||
|  |         sourceFolder: dist | ||||||
|  |         contents: '*.zip' | ||||||
|  |         targetFolder: $(Build.ArtifactStagingDirectory) | ||||||
|     - task: PublishPipelineArtifact@0 |     - task: PublishPipelineArtifact@0 | ||||||
|       inputs: |       inputs: | ||||||
|         artifactName: 'UbuntuArm64' |         artifactName: 'UbuntuArm64' | ||||||
|  |  | ||||||
|  | @ -123,6 +123,7 @@ extern "C" { | ||||||
|         Z3_CATCH_RETURN(nullptr); |         Z3_CATCH_RETURN(nullptr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     MK_UNARY(Z3_mk_abs, mk_c(c)->get_arith_fid(), OP_ABS, SKIP); | ||||||
|     MK_UNARY(Z3_mk_int2real, mk_c(c)->get_arith_fid(), OP_TO_REAL, SKIP); |     MK_UNARY(Z3_mk_int2real, mk_c(c)->get_arith_fid(), OP_TO_REAL, SKIP); | ||||||
|     MK_UNARY(Z3_mk_real2int, mk_c(c)->get_arith_fid(), OP_TO_INT, SKIP); |     MK_UNARY(Z3_mk_real2int, mk_c(c)->get_arith_fid(), OP_TO_INT, SKIP); | ||||||
|     MK_UNARY(Z3_mk_is_int,   mk_c(c)->get_arith_fid(), OP_IS_INT, SKIP); |     MK_UNARY(Z3_mk_is_int,   mk_c(c)->get_arith_fid(), OP_IS_INT, SKIP); | ||||||
|  |  | ||||||
|  | @ -1152,6 +1152,7 @@ extern "C" { | ||||||
|             case OP_REM: return Z3_OP_REM; |             case OP_REM: return Z3_OP_REM; | ||||||
|             case OP_MOD: return Z3_OP_MOD; |             case OP_MOD: return Z3_OP_MOD; | ||||||
|             case OP_POWER: return Z3_OP_POWER; |             case OP_POWER: return Z3_OP_POWER; | ||||||
|  |             case OP_ABS: return Z3_OP_ABS; | ||||||
|             case OP_TO_REAL: return Z3_OP_TO_REAL; |             case OP_TO_REAL: return Z3_OP_TO_REAL; | ||||||
|             case OP_TO_INT: return Z3_OP_TO_INT; |             case OP_TO_INT: return Z3_OP_TO_INT; | ||||||
|             case OP_IS_INT: return Z3_OP_IS_INT; |             case OP_IS_INT: return Z3_OP_IS_INT; | ||||||
|  | @ -1310,6 +1311,10 @@ extern "C" { | ||||||
|             case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX; |             case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX; | ||||||
|             case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE; |             case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE; | ||||||
|             case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE; |             case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE; | ||||||
|  |             case OP_SEQ_MAP: return Z3_OP_SEQ_MAP; | ||||||
|  |             case OP_SEQ_MAPI: return Z3_OP_SEQ_MAPI; | ||||||
|  |             case OP_SEQ_FOLDL: return Z3_OP_SEQ_FOLDL; | ||||||
|  |             case OP_SEQ_FOLDLI: return Z3_OP_SEQ_FOLDLI; | ||||||
| 
 | 
 | ||||||
|             case _OP_STRING_STRREPL: return Z3_OP_SEQ_REPLACE; |             case _OP_STRING_STRREPL: return Z3_OP_SEQ_REPLACE; | ||||||
|             case _OP_STRING_CONCAT: return Z3_OP_SEQ_CONCAT; |             case _OP_STRING_CONCAT: return Z3_OP_SEQ_CONCAT; | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ Revision History: | ||||||
| 
 | 
 | ||||||
| --*/ | --*/ | ||||||
| #include<typeinfo> | #include<typeinfo> | ||||||
|  | #include "util/debug.h" | ||||||
| #include "util/z3_version.h" | #include "util/z3_version.h" | ||||||
| #include "api/api_context.h" | #include "api/api_context.h" | ||||||
| #include "ast/ast_pp.h" | #include "ast/ast_pp.h" | ||||||
|  | @ -393,6 +394,7 @@ extern "C" { | ||||||
|         Z3_TRY; |         Z3_TRY; | ||||||
|         LOG_Z3_mk_context_rc(c); |         LOG_Z3_mk_context_rc(c); | ||||||
|         memory::initialize(UINT_MAX); |         memory::initialize(UINT_MAX); | ||||||
|  |         set_default_exit_action(exit_action::throw_exception); | ||||||
|         Z3_context r = reinterpret_cast<Z3_context>(alloc(api::context, reinterpret_cast<ast_context_params*>(c), true)); |         Z3_context r = reinterpret_cast<Z3_context>(alloc(api::context, reinterpret_cast<ast_context_params*>(c), true)); | ||||||
|         RETURN_Z3(r); |         RETURN_Z3(r); | ||||||
|         Z3_CATCH_RETURN_NO_HANDLE(nullptr); |         Z3_CATCH_RETURN_NO_HANDLE(nullptr); | ||||||
|  |  | ||||||
|  | @ -348,5 +348,10 @@ extern "C" { | ||||||
|     MK_UNARY(Z3_mk_char_from_bv, mk_c(c)->get_char_fid(), OP_CHAR_FROM_BV, SKIP); |     MK_UNARY(Z3_mk_char_from_bv, mk_c(c)->get_char_fid(), OP_CHAR_FROM_BV, SKIP); | ||||||
|     MK_UNARY(Z3_mk_char_is_digit, mk_c(c)->get_char_fid(), OP_CHAR_IS_DIGIT, SKIP); |     MK_UNARY(Z3_mk_char_is_digit, mk_c(c)->get_char_fid(), OP_CHAR_IS_DIGIT, SKIP); | ||||||
| 
 | 
 | ||||||
|  |     MK_BINARY(Z3_mk_seq_map, mk_c(c)->get_seq_fid(), OP_SEQ_MAP, SKIP);  | ||||||
|  |     MK_TERNARY(Z3_mk_seq_mapi, mk_c(c)->get_seq_fid(), OP_SEQ_MAPI, SKIP); | ||||||
|  |     MK_TERNARY(Z3_mk_seq_foldl, mk_c(c)->get_seq_fid(), OP_SEQ_FOLDL, SKIP); | ||||||
|  |     MK_FOURARY(Z3_mk_seq_foldli, mk_c(c)->get_seq_fid(), OP_SEQ_FOLDLI, SKIP); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -160,6 +160,23 @@ Z3_ast Z3_API NAME(Z3_context c, Z3_ast n1, Z3_ast n2) {        \ | ||||||
|     MK_TERNARY_BODY(NAME, FID, OP, EXTRA_CODE);                          \ |     MK_TERNARY_BODY(NAME, FID, OP, EXTRA_CODE);                          \ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define MK_FOURARY_BODY(NAME, FID, OP, EXTRA_CODE)               \ | ||||||
|  |     Z3_TRY;                                                     \ | ||||||
|  |     RESET_ERROR_CODE();                                         \ | ||||||
|  |     EXTRA_CODE;                                                 \ | ||||||
|  |     expr * args[4] = { to_expr(n1), to_expr(n2), to_expr(n3), to_expr(n4) }; \ | ||||||
|  |     ast* a = mk_c(c)->m().mk_app(FID, OP, 0, 0, 4, args);       \ | ||||||
|  |     mk_c(c)->save_ast_trail(a);                                 \ | ||||||
|  |     check_sorts(c, a);                                          \ | ||||||
|  |     RETURN_Z3(of_ast(a));                                       \ | ||||||
|  |     Z3_CATCH_RETURN(0); | ||||||
|  | 
 | ||||||
|  | #define MK_FOURARY(NAME, FID, OP, EXTRA_CODE)                            \ | ||||||
|  |     Z3_ast Z3_API NAME(Z3_context c, Z3_ast n1, Z3_ast n2, Z3_ast n3, Z3_ast n4) { \ | ||||||
|  |     LOG_ ## NAME(c, n1, n2, n3, n4);                                        \ | ||||||
|  |     MK_FOURARY_BODY(NAME, FID, OP, EXTRA_CODE);                          \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #define MK_NARY(NAME, FID, OP, EXTRA_CODE)                              \ | #define MK_NARY(NAME, FID, OP, EXTRA_CODE)                              \ | ||||||
| Z3_ast Z3_API NAME(Z3_context c, unsigned num_args, Z3_ast const* args) { \ | Z3_ast Z3_API NAME(Z3_context c, unsigned num_args, Z3_ast const* args) { \ | ||||||
|     Z3_TRY;                                                             \ |     Z3_TRY;                                                             \ | ||||||
|  |  | ||||||
|  | @ -470,6 +470,7 @@ namespace z3 { | ||||||
|         context * m_ctx; |         context * m_ctx; | ||||||
|     public: |     public: | ||||||
|         object(context & c):m_ctx(&c) {} |         object(context & c):m_ctx(&c) {} | ||||||
|  |         virtual ~object() = default; | ||||||
|         context & ctx() const { return *m_ctx; } |         context & ctx() const { return *m_ctx; } | ||||||
|         Z3_error_code check_error() const { return m_ctx->check_error(); } |         Z3_error_code check_error() const { return m_ctx->check_error(); } | ||||||
|         friend void check_context(object const & a, object const & b); |         friend void check_context(object const & a, object const & b); | ||||||
|  | @ -508,7 +509,7 @@ namespace z3 { | ||||||
|             object::operator=(o); |             object::operator=(o); | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
|         ~param_descrs() { Z3_param_descrs_dec_ref(ctx(), m_descrs); } |         ~param_descrs() override { Z3_param_descrs_dec_ref(ctx(), m_descrs); } | ||||||
|         static param_descrs simplify_param_descrs(context& c) { return param_descrs(c, Z3_simplify_get_param_descrs(c)); } |         static param_descrs simplify_param_descrs(context& c) { return param_descrs(c, Z3_simplify_get_param_descrs(c)); } | ||||||
|         static param_descrs global_param_descrs(context& c) { return param_descrs(c, Z3_get_global_param_descrs(c)); } |         static param_descrs global_param_descrs(context& c) { return param_descrs(c, Z3_get_global_param_descrs(c)); } | ||||||
| 
 | 
 | ||||||
|  | @ -526,7 +527,7 @@ namespace z3 { | ||||||
|     public: |     public: | ||||||
|         params(context & c):object(c) { m_params = Z3_mk_params(c); Z3_params_inc_ref(ctx(), m_params); } |         params(context & c):object(c) { m_params = Z3_mk_params(c); Z3_params_inc_ref(ctx(), m_params); } | ||||||
|         params(params const & s):object(s), m_params(s.m_params) { Z3_params_inc_ref(ctx(), m_params); } |         params(params const & s):object(s), m_params(s.m_params) { Z3_params_inc_ref(ctx(), m_params); } | ||||||
|         ~params() { Z3_params_dec_ref(ctx(), m_params); } |         ~params() override { Z3_params_dec_ref(ctx(), m_params); } | ||||||
|         operator Z3_params() const { return m_params; } |         operator Z3_params() const { return m_params; } | ||||||
|         params & operator=(params const & s) { |         params & operator=(params const & s) { | ||||||
|             Z3_params_inc_ref(s.ctx(), s.m_params); |             Z3_params_inc_ref(s.ctx(), s.m_params); | ||||||
|  | @ -554,7 +555,7 @@ namespace z3 { | ||||||
|         ast(context & c):object(c), m_ast(0) {} |         ast(context & c):object(c), m_ast(0) {} | ||||||
|         ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); } |         ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); } | ||||||
|         ast(ast const & s) :object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } |         ast(ast const & s) :object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } | ||||||
|         ~ast() { if (m_ast) { Z3_dec_ref(*m_ctx, m_ast); } } |         ~ast() override { if (m_ast) { Z3_dec_ref(*m_ctx, m_ast); } } | ||||||
|         operator Z3_ast() const { return m_ast; } |         operator Z3_ast() const { return m_ast; } | ||||||
|         operator bool() const { return m_ast != 0; } |         operator bool() const { return m_ast != 0; } | ||||||
|         ast & operator=(ast const & s) { |         ast & operator=(ast const & s) { | ||||||
|  | @ -592,7 +593,7 @@ namespace z3 { | ||||||
|         ast_vector_tpl(ast_vector_tpl const & s):object(s), m_vector(s.m_vector) { Z3_ast_vector_inc_ref(ctx(), m_vector); } |         ast_vector_tpl(ast_vector_tpl const & s):object(s), m_vector(s.m_vector) { Z3_ast_vector_inc_ref(ctx(), m_vector); } | ||||||
|         ast_vector_tpl(context& c, ast_vector_tpl const& src): object(c) { init(Z3_ast_vector_translate(src.ctx(), src, c)); } |         ast_vector_tpl(context& c, ast_vector_tpl const& src): object(c) { init(Z3_ast_vector_translate(src.ctx(), src, c)); } | ||||||
| 
 | 
 | ||||||
|         ~ast_vector_tpl() { Z3_ast_vector_dec_ref(ctx(), m_vector); } |         ~ast_vector_tpl() override { Z3_ast_vector_dec_ref(ctx(), m_vector); } | ||||||
|         operator Z3_ast_vector() const { return m_vector; } |         operator Z3_ast_vector() const { return m_vector; } | ||||||
|         unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); } |         unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); } | ||||||
|         T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); } |         T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); } | ||||||
|  | @ -2496,6 +2497,34 @@ namespace z3 { | ||||||
|         return expr(ctx, r); |         return expr(ctx, r); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     inline expr map(expr const& f, expr const& list) { | ||||||
|  |         context& ctx = f.ctx(); | ||||||
|  |         Z3_ast r = Z3_mk_seq_map(ctx, f, list); | ||||||
|  |         ctx.check_error(); | ||||||
|  |         return expr(ctx, r); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline expr mapi(expr const& f, expr const& i, expr const& list) { | ||||||
|  |         context& ctx = f.ctx(); | ||||||
|  |         Z3_ast r = Z3_mk_seq_mapi(ctx, f, i, list); | ||||||
|  |         ctx.check_error(); | ||||||
|  |         return expr(ctx, r); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline expr foldl(expr const& f, expr const& a, expr const& list) { | ||||||
|  |         context& ctx = f.ctx(); | ||||||
|  |         Z3_ast r = Z3_mk_seq_foldl(ctx, f, a, list); | ||||||
|  |         ctx.check_error(); | ||||||
|  |         return expr(ctx, r); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline expr foldli(expr const& f, expr const& i, expr const& a, expr const& list) { | ||||||
|  |         context& ctx = f.ctx(); | ||||||
|  |         Z3_ast r = Z3_mk_seq_foldli(ctx, f, i, a, list); | ||||||
|  |         ctx.check_error(); | ||||||
|  |         return expr(ctx, r); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     inline expr mk_or(expr_vector const& args) { |     inline expr mk_or(expr_vector const& args) { | ||||||
|         array<Z3_ast> _args(args); |         array<Z3_ast> _args(args); | ||||||
|         Z3_ast r = Z3_mk_or(args.ctx(), _args.size(), _args.ptr()); |         Z3_ast r = Z3_mk_or(args.ctx(), _args.size(), _args.ptr()); | ||||||
|  | @ -2527,7 +2556,7 @@ namespace z3 { | ||||||
|     public: |     public: | ||||||
|         func_entry(context & c, Z3_func_entry e):object(c) { init(e); } |         func_entry(context & c, Z3_func_entry e):object(c) { init(e); } | ||||||
|         func_entry(func_entry const & s):object(s) { init(s.m_entry); } |         func_entry(func_entry const & s):object(s) { init(s.m_entry); } | ||||||
|         ~func_entry() { Z3_func_entry_dec_ref(ctx(), m_entry); } |         ~func_entry() override { Z3_func_entry_dec_ref(ctx(), m_entry); } | ||||||
|         operator Z3_func_entry() const { return m_entry; } |         operator Z3_func_entry() const { return m_entry; } | ||||||
|         func_entry & operator=(func_entry const & s) { |         func_entry & operator=(func_entry const & s) { | ||||||
|             Z3_func_entry_inc_ref(s.ctx(), s.m_entry); |             Z3_func_entry_inc_ref(s.ctx(), s.m_entry); | ||||||
|  | @ -2550,7 +2579,7 @@ namespace z3 { | ||||||
|     public: |     public: | ||||||
|         func_interp(context & c, Z3_func_interp e):object(c) { init(e); } |         func_interp(context & c, Z3_func_interp e):object(c) { init(e); } | ||||||
|         func_interp(func_interp const & s):object(s) { init(s.m_interp); } |         func_interp(func_interp const & s):object(s) { init(s.m_interp); } | ||||||
|         ~func_interp() { Z3_func_interp_dec_ref(ctx(), m_interp); } |         ~func_interp() override { Z3_func_interp_dec_ref(ctx(), m_interp); } | ||||||
|         operator Z3_func_interp() const { return m_interp; } |         operator Z3_func_interp() const { return m_interp; } | ||||||
|         func_interp & operator=(func_interp const & s) { |         func_interp & operator=(func_interp const & s) { | ||||||
|             Z3_func_interp_inc_ref(s.ctx(), s.m_interp); |             Z3_func_interp_inc_ref(s.ctx(), s.m_interp); | ||||||
|  | @ -2584,7 +2613,7 @@ namespace z3 { | ||||||
|         model(context & c, Z3_model m):object(c) { init(m); } |         model(context & c, Z3_model m):object(c) { init(m); } | ||||||
|         model(model const & s):object(s) { init(s.m_model); } |         model(model const & s):object(s) { init(s.m_model); } | ||||||
|         model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } |         model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } | ||||||
|         ~model() { Z3_model_dec_ref(ctx(), m_model); } |         ~model() override { Z3_model_dec_ref(ctx(), m_model); } | ||||||
|         operator Z3_model() const { return m_model; } |         operator Z3_model() const { return m_model; } | ||||||
|         model & operator=(model const & s) { |         model & operator=(model const & s) { | ||||||
|             Z3_model_inc_ref(s.ctx(), s.m_model); |             Z3_model_inc_ref(s.ctx(), s.m_model); | ||||||
|  | @ -2664,7 +2693,7 @@ namespace z3 { | ||||||
|         stats(context & c):object(c), m_stats(0) {} |         stats(context & c):object(c), m_stats(0) {} | ||||||
|         stats(context & c, Z3_stats e):object(c) { init(e); } |         stats(context & c, Z3_stats e):object(c) { init(e); } | ||||||
|         stats(stats const & s):object(s) { init(s.m_stats); } |         stats(stats const & s):object(s) { init(s.m_stats); } | ||||||
|         ~stats() { if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); } |         ~stats() override { if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); } | ||||||
|         operator Z3_stats() const { return m_stats; } |         operator Z3_stats() const { return m_stats; } | ||||||
|         stats & operator=(stats const & s) { |         stats & operator=(stats const & s) { | ||||||
|             Z3_stats_inc_ref(s.ctx(), s.m_stats); |             Z3_stats_inc_ref(s.ctx(), s.m_stats); | ||||||
|  | @ -2746,7 +2775,7 @@ namespace z3 { | ||||||
|         solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); } |         solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); } | ||||||
|         solver(solver const & s):object(s) { init(s.m_solver); } |         solver(solver const & s):object(s) { init(s.m_solver); } | ||||||
|         solver(solver const& s, simplifier const& simp); |         solver(solver const& s, simplifier const& simp); | ||||||
|         ~solver() { Z3_solver_dec_ref(ctx(), m_solver); } |         ~solver() override { Z3_solver_dec_ref(ctx(), m_solver); } | ||||||
|         operator Z3_solver() const { return m_solver; } |         operator Z3_solver() const { return m_solver; } | ||||||
|         solver & operator=(solver const & s) { |         solver & operator=(solver const & s) { | ||||||
|             Z3_solver_inc_ref(s.ctx(), s.m_solver); |             Z3_solver_inc_ref(s.ctx(), s.m_solver); | ||||||
|  | @ -2967,7 +2996,7 @@ namespace z3 { | ||||||
|         goal(context & c, bool models=true, bool unsat_cores=false, bool proofs=false):object(c) { init(Z3_mk_goal(c, models, unsat_cores, proofs)); } |         goal(context & c, bool models=true, bool unsat_cores=false, bool proofs=false):object(c) { init(Z3_mk_goal(c, models, unsat_cores, proofs)); } | ||||||
|         goal(context & c, Z3_goal s):object(c) { init(s); } |         goal(context & c, Z3_goal s):object(c) { init(s); } | ||||||
|         goal(goal const & s):object(s) { init(s.m_goal); } |         goal(goal const & s):object(s) { init(s.m_goal); } | ||||||
|         ~goal() { Z3_goal_dec_ref(ctx(), m_goal); } |         ~goal() override { Z3_goal_dec_ref(ctx(), m_goal); } | ||||||
|         operator Z3_goal() const { return m_goal; } |         operator Z3_goal() const { return m_goal; } | ||||||
|         goal & operator=(goal const & s) { |         goal & operator=(goal const & s) { | ||||||
|             Z3_goal_inc_ref(s.ctx(), s.m_goal); |             Z3_goal_inc_ref(s.ctx(), s.m_goal); | ||||||
|  | @ -3025,7 +3054,7 @@ namespace z3 { | ||||||
|     public: |     public: | ||||||
|         apply_result(context & c, Z3_apply_result s):object(c) { init(s); } |         apply_result(context & c, Z3_apply_result s):object(c) { init(s); } | ||||||
|         apply_result(apply_result const & s):object(s) { init(s.m_apply_result); } |         apply_result(apply_result const & s):object(s) { init(s.m_apply_result); } | ||||||
|         ~apply_result() { Z3_apply_result_dec_ref(ctx(), m_apply_result); } |         ~apply_result() override { Z3_apply_result_dec_ref(ctx(), m_apply_result); } | ||||||
|         operator Z3_apply_result() const { return m_apply_result; } |         operator Z3_apply_result() const { return m_apply_result; } | ||||||
|         apply_result & operator=(apply_result const & s) { |         apply_result & operator=(apply_result const & s) { | ||||||
|             Z3_apply_result_inc_ref(s.ctx(), s.m_apply_result); |             Z3_apply_result_inc_ref(s.ctx(), s.m_apply_result); | ||||||
|  | @ -3050,7 +3079,7 @@ namespace z3 { | ||||||
|         tactic(context & c, char const * name):object(c) { Z3_tactic r = Z3_mk_tactic(c, name); check_error(); init(r); } |         tactic(context & c, char const * name):object(c) { Z3_tactic r = Z3_mk_tactic(c, name); check_error(); init(r); } | ||||||
|         tactic(context & c, Z3_tactic s):object(c) { init(s); } |         tactic(context & c, Z3_tactic s):object(c) { init(s); } | ||||||
|         tactic(tactic const & s):object(s) { init(s.m_tactic); } |         tactic(tactic const & s):object(s) { init(s.m_tactic); } | ||||||
|         ~tactic() { Z3_tactic_dec_ref(ctx(), m_tactic); } |         ~tactic() override { Z3_tactic_dec_ref(ctx(), m_tactic); } | ||||||
|         operator Z3_tactic() const { return m_tactic; } |         operator Z3_tactic() const { return m_tactic; } | ||||||
|         tactic & operator=(tactic const & s) { |         tactic & operator=(tactic const & s) { | ||||||
|             Z3_tactic_inc_ref(s.ctx(), s.m_tactic); |             Z3_tactic_inc_ref(s.ctx(), s.m_tactic); | ||||||
|  | @ -3136,7 +3165,7 @@ namespace z3 { | ||||||
|         simplifier(context & c, char const * name):object(c) { Z3_simplifier r = Z3_mk_simplifier(c, name); check_error(); init(r); } |         simplifier(context & c, char const * name):object(c) { Z3_simplifier r = Z3_mk_simplifier(c, name); check_error(); init(r); } | ||||||
|         simplifier(context & c, Z3_simplifier s):object(c) { init(s); } |         simplifier(context & c, Z3_simplifier s):object(c) { init(s); } | ||||||
|         simplifier(simplifier const & s):object(s) { init(s.m_simplifier); } |         simplifier(simplifier const & s):object(s) { init(s.m_simplifier); } | ||||||
|         ~simplifier() { Z3_simplifier_dec_ref(ctx(), m_simplifier); } |         ~simplifier() override { Z3_simplifier_dec_ref(ctx(), m_simplifier); } | ||||||
|         operator Z3_simplifier() const { return m_simplifier; } |         operator Z3_simplifier() const { return m_simplifier; } | ||||||
|         simplifier & operator=(simplifier const & s) { |         simplifier & operator=(simplifier const & s) { | ||||||
|             Z3_simplifier_inc_ref(s.ctx(), s.m_simplifier); |             Z3_simplifier_inc_ref(s.ctx(), s.m_simplifier); | ||||||
|  | @ -3178,7 +3207,7 @@ namespace z3 { | ||||||
|         probe(context & c, double val):object(c) { Z3_probe r = Z3_probe_const(c, val); check_error(); init(r); } |         probe(context & c, double val):object(c) { Z3_probe r = Z3_probe_const(c, val); check_error(); init(r); } | ||||||
|         probe(context & c, Z3_probe s):object(c) { init(s); } |         probe(context & c, Z3_probe s):object(c) { init(s); } | ||||||
|         probe(probe const & s):object(s) { init(s.m_probe); } |         probe(probe const & s):object(s) { init(s.m_probe); } | ||||||
|         ~probe() { Z3_probe_dec_ref(ctx(), m_probe); } |         ~probe() override { Z3_probe_dec_ref(ctx(), m_probe); } | ||||||
|         operator Z3_probe() const { return m_probe; } |         operator Z3_probe() const { return m_probe; } | ||||||
|         probe & operator=(probe const & s) { |         probe & operator=(probe const & s) { | ||||||
|             Z3_probe_inc_ref(s.ctx(), s.m_probe); |             Z3_probe_inc_ref(s.ctx(), s.m_probe); | ||||||
|  | @ -3272,7 +3301,7 @@ namespace z3 { | ||||||
|             object::operator=(o); |             object::operator=(o); | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
|         ~optimize() { Z3_optimize_dec_ref(ctx(), m_opt); } |         ~optimize() override { Z3_optimize_dec_ref(ctx(), m_opt); } | ||||||
|         operator Z3_optimize() const { return m_opt; } |         operator Z3_optimize() const { return m_opt; } | ||||||
|         void add(expr const& e) { |         void add(expr const& e) { | ||||||
|             assert(e.is_bool()); |             assert(e.is_bool()); | ||||||
|  | @ -3353,7 +3382,7 @@ namespace z3 { | ||||||
|     public: |     public: | ||||||
|         fixedpoint(context& c):object(c) { m_fp = Z3_mk_fixedpoint(c); Z3_fixedpoint_inc_ref(c, m_fp); } |         fixedpoint(context& c):object(c) { m_fp = Z3_mk_fixedpoint(c); Z3_fixedpoint_inc_ref(c, m_fp); } | ||||||
|         fixedpoint(fixedpoint const & o):object(o), m_fp(o.m_fp) { Z3_fixedpoint_inc_ref(ctx(), m_fp); } |         fixedpoint(fixedpoint const & o):object(o), m_fp(o.m_fp) { Z3_fixedpoint_inc_ref(ctx(), m_fp); } | ||||||
|         ~fixedpoint() { Z3_fixedpoint_dec_ref(ctx(), m_fp); } |         ~fixedpoint() override { Z3_fixedpoint_dec_ref(ctx(), m_fp); } | ||||||
|         fixedpoint & operator=(fixedpoint const & o) { |         fixedpoint & operator=(fixedpoint const & o) { | ||||||
|             Z3_fixedpoint_inc_ref(o.ctx(), o.m_fp); |             Z3_fixedpoint_inc_ref(o.ctx(), o.m_fp); | ||||||
|             Z3_fixedpoint_dec_ref(ctx(), m_fp); |             Z3_fixedpoint_dec_ref(ctx(), m_fp); | ||||||
|  |  | ||||||
|  | @ -11210,6 +11210,32 @@ def Length(s): | ||||||
|     s = _coerce_seq(s) |     s = _coerce_seq(s) | ||||||
|     return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx) |     return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx) | ||||||
| 
 | 
 | ||||||
|  | def SeqMap(f, s): | ||||||
|  |     """Map function 'f' over sequence 's'""" | ||||||
|  |     ctx = _get_ctx2(f, s) | ||||||
|  |     s = _coerce_seq(s, ctx) | ||||||
|  |     return _to_expr_ref(Z3_mk_seq_map(s.ctx_ref(), f.as_ast(), s.as_ast()), ctx) | ||||||
|  | 
 | ||||||
|  | def SeqMapI(f, i, s): | ||||||
|  |     """Map function 'f' over sequence 's' at index 'i'""" | ||||||
|  |     ctx = _get_ctx(f, s) | ||||||
|  |     s = _coerce_seq(s, ctx) | ||||||
|  |     if not is_expr(i): | ||||||
|  |         i = _py2expr(i) | ||||||
|  |     return _to_expr_ref(Z3_mk_seq_mapi(s.ctx_ref(), f.as_ast(), i.as_ast(), s.as_ast()), ctx) | ||||||
|  | 
 | ||||||
|  | def SeqFoldLeft(f, a, s): | ||||||
|  |     ctx = _get_ctx2(f, s) | ||||||
|  |     s = _coerce_seq(s, ctx) | ||||||
|  |     a = _py2expr(a) | ||||||
|  |     return _to_expr_ref(Z3_mk_seq_foldl(s.ctx_ref(), f.as_ast(), a.as_ast(), s.as_ast()), ctx) | ||||||
|  | 
 | ||||||
|  | def SeqFoldLeftI(f, i, a, s): | ||||||
|  |     ctx = _get_ctx2(f, s) | ||||||
|  |     s = _coerce_seq(s, ctx) | ||||||
|  |     a = _py2expr(a) | ||||||
|  |     i = _py2epxr(i) | ||||||
|  |     return _to_expr_ref(Z3_mk_seq_foldli(s.ctx_ref(), f.as_ast(), i.as_ast(), a.as_ast(), s.as_ast()), ctx) | ||||||
| 
 | 
 | ||||||
| def StrToInt(s): | def StrToInt(s): | ||||||
|     """Convert string expression to integer |     """Convert string expression to integer | ||||||
|  |  | ||||||
|  | @ -1023,6 +1023,7 @@ typedef enum { | ||||||
|     Z3_OP_TO_INT, |     Z3_OP_TO_INT, | ||||||
|     Z3_OP_IS_INT, |     Z3_OP_IS_INT, | ||||||
|     Z3_OP_POWER, |     Z3_OP_POWER, | ||||||
|  |     Z3_OP_ABS, | ||||||
| 
 | 
 | ||||||
|     // Arrays & Sets
 |     // Arrays & Sets
 | ||||||
|     Z3_OP_STORE = 0x300, |     Z3_OP_STORE = 0x300, | ||||||
|  | @ -1193,6 +1194,10 @@ typedef enum { | ||||||
|     Z3_OP_SEQ_LAST_INDEX, |     Z3_OP_SEQ_LAST_INDEX, | ||||||
|     Z3_OP_SEQ_TO_RE, |     Z3_OP_SEQ_TO_RE, | ||||||
|     Z3_OP_SEQ_IN_RE, |     Z3_OP_SEQ_IN_RE, | ||||||
|  |     Z3_OP_SEQ_MAP,             | ||||||
|  |     Z3_OP_SEQ_MAPI,            | ||||||
|  |     Z3_OP_SEQ_FOLDL,           | ||||||
|  |     Z3_OP_SEQ_FOLDLI,          | ||||||
| 
 | 
 | ||||||
|     // strings
 |     // strings
 | ||||||
|     Z3_OP_STR_TO_INT, |     Z3_OP_STR_TO_INT, | ||||||
|  | @ -2544,6 +2549,13 @@ extern "C" { | ||||||
|     */ |     */ | ||||||
|     Z3_ast Z3_API Z3_mk_power(Z3_context c, Z3_ast arg1, Z3_ast arg2); |     Z3_ast Z3_API Z3_mk_power(Z3_context c, Z3_ast arg1, Z3_ast arg2); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |        \brief Take the absolute value of an integer | ||||||
|  | 
 | ||||||
|  |        def_API('Z3_mk_abs', AST, (_in(CONTEXT), _in(AST))) | ||||||
|  |     */ | ||||||
|  |     Z3_ast Z3_API Z3_mk_abs(Z3_context c, Z3_ast arg); | ||||||
|  |      | ||||||
|     /**
 |     /**
 | ||||||
|         \brief Create less than. |         \brief Create less than. | ||||||
| 
 | 
 | ||||||
|  | @ -3798,6 +3810,30 @@ extern "C" { | ||||||
|     */ |     */ | ||||||
|     Z3_ast Z3_API Z3_mk_seq_last_index(Z3_context c, Z3_ast s, Z3_ast substr); |     Z3_ast Z3_API Z3_mk_seq_last_index(Z3_context c, Z3_ast s, Z3_ast substr); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |       \brief Create a map of the function \c f over the sequence \c s. | ||||||
|  |       def_API('Z3_mk_seq_map', AST ,(_in(CONTEXT), _in(AST), _in(AST))) | ||||||
|  |     */ | ||||||
|  |     Z3_ast Z3_API Z3_mk_seq_map(Z3_context c, Z3_ast f, Z3_ast s); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      \brief Create a map of the function \c f over the sequence \c s starting at index \c i. | ||||||
|  |      def_API('Z3_mk_seq_mapi', AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) | ||||||
|  |     */ | ||||||
|  |     Z3_ast Z3_API Z3_mk_seq_mapi(Z3_context c, Z3_ast f, Z3_ast i, Z3_ast s); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |       \brief Create a fold of the function \c f over the sequence \c s with accumulator a. | ||||||
|  |       def_API('Z3_mk_seq_foldl', AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) | ||||||
|  |     */ | ||||||
|  |     Z3_ast Z3_API Z3_mk_seq_foldl(Z3_context c, Z3_ast f, Z3_ast a, Z3_ast s); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |        \brief Create a fold with index tracking of the function \c f over the sequence \c s with accumulator \c a starting at index \c i. | ||||||
|  |        def_API('Z3_mk_seq_foldli', AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST), _in(AST))) | ||||||
|  |     */ | ||||||
|  |     Z3_ast Z3_API Z3_mk_seq_foldli(Z3_context c, Z3_ast f, Z3_ast i, Z3_ast a, Z3_ast s); | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|        \brief Convert string to integer. |        \brief Convert string to integer. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -438,6 +438,7 @@ public: | ||||||
|     MATCH_BINARY(is_bv_xor); |     MATCH_BINARY(is_bv_xor); | ||||||
|     MATCH_BINARY(is_bv_nand); |     MATCH_BINARY(is_bv_nand); | ||||||
|     MATCH_BINARY(is_bv_nor); |     MATCH_BINARY(is_bv_nor); | ||||||
|  |     MATCH_BINARY(is_concat); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     MATCH_BINARY(is_bv_uremi); |     MATCH_BINARY(is_bv_uremi); | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ Notes: | ||||||
| 
 | 
 | ||||||
| --*/ | --*/ | ||||||
| #include "params/rewriter_params.hpp" | #include "params/rewriter_params.hpp" | ||||||
|  | #include "params/poly_rewriter_params.hpp" | ||||||
| #include "ast/rewriter/th_rewriter.h" | #include "ast/rewriter/th_rewriter.h" | ||||||
| #include "ast/rewriter/bool_rewriter.h" | #include "ast/rewriter/bool_rewriter.h" | ||||||
| #include "ast/rewriter/arith_rewriter.h" | #include "ast/rewriter/arith_rewriter.h" | ||||||
|  | @ -83,7 +84,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { | ||||||
| 
 | 
 | ||||||
|     void updt_local_params(params_ref const & _p) { |     void updt_local_params(params_ref const & _p) { | ||||||
|         rewriter_params p(_p); |         rewriter_params p(_p); | ||||||
|         m_flat           = true; |         poly_rewriter_params pp(_p); | ||||||
|  |         m_flat           = pp.flat(); | ||||||
|         m_max_memory     = megabytes_to_bytes(p.max_memory()); |         m_max_memory     = megabytes_to_bytes(p.max_memory()); | ||||||
|         m_max_steps      = p.max_steps(); |         m_max_steps      = p.max_steps(); | ||||||
|         m_pull_cheap_ite = p.pull_cheap_ite(); |         m_pull_cheap_ite = p.pull_cheap_ite(); | ||||||
|  |  | ||||||
|  | @ -289,6 +289,7 @@ void bound_simplifier::tighten_bound(dependent_expr const& de) { | ||||||
| void bound_simplifier::assert_upper(expr* x, rational const& n, bool strict) { | void bound_simplifier::assert_upper(expr* x, rational const& n, bool strict) { | ||||||
|     scoped_mpq c(nm); |     scoped_mpq c(nm); | ||||||
|     nm.set(c, n.to_mpq()); |     nm.set(c, n.to_mpq()); | ||||||
|  |     TRACE("propagate-ineqs", tout << to_var(x) << ": " << mk_pp(x, m) << (strict ? " < " : " <= ") << n << "\n"); | ||||||
|     bp.assert_upper(to_var(x), c, strict); |     bp.assert_upper(to_var(x), c, strict); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -296,6 +297,7 @@ void bound_simplifier::assert_upper(expr* x, rational const& n, bool strict) { | ||||||
| void bound_simplifier::assert_lower(expr* x, rational const& n, bool strict) { | void bound_simplifier::assert_lower(expr* x, rational const& n, bool strict) { | ||||||
|     scoped_mpq c(nm); |     scoped_mpq c(nm); | ||||||
|     nm.set(c, n.to_mpq()); |     nm.set(c, n.to_mpq()); | ||||||
|  |     TRACE("propagate-ineqs", tout <<  to_var(x) << ": " << mk_pp(x, m) << (strict ? " > " : " >= ") << n << "\n"); | ||||||
|     bp.assert_lower(to_var(x), c, strict); |     bp.assert_lower(to_var(x), c, strict); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -306,6 +308,7 @@ bool bound_simplifier::has_lower(expr* x, rational& n, bool& strict) { | ||||||
|         return false; |         return false; | ||||||
|     strict = m_interval.lower_is_open(i); |     strict = m_interval.lower_is_open(i); | ||||||
|     n = m_interval.lower(i); |     n = m_interval.lower(i); | ||||||
|  |     TRACE("propagate-ineqs", tout <<  to_var(x) << ": " << mk_pp(x, m) << (strict ? " > " : " >= ") << n << "\n"); | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -316,6 +319,7 @@ bool bound_simplifier::has_upper(expr* x, rational& n, bool& strict) { | ||||||
|         return false; |         return false; | ||||||
|     strict = m_interval.upper_is_open(i); |     strict = m_interval.upper_is_open(i); | ||||||
|     n = m_interval.upper(i); |     n = m_interval.upper(i); | ||||||
|  |     TRACE("propagate-ineqs", tout << to_var(x) << ": " << mk_pp(x, m) << (strict ? " < " : " <= ") << n << "\n"); | ||||||
|     return true;   |     return true;   | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,8 +31,9 @@ namespace euf { | ||||||
|         expr* orig;       // original expression that encoded equation
 |         expr* orig;       // original expression that encoded equation
 | ||||||
|         app* var;         // isolated variable
 |         app* var;         // isolated variable
 | ||||||
|         expr_ref term;    // defined term
 |         expr_ref term;    // defined term
 | ||||||
|         expr_dependency* dep; |         expr_dependency_ref dep; | ||||||
|         dependent_eq(expr* orig, app* var, expr_ref const& term, expr_dependency* d) : orig(orig), var(var), term(term), dep(d) {} |         dependent_eq(expr* orig, app* var, expr_ref const& term, expr_dependency* d) :  | ||||||
|  |             orig(orig), var(var), term(term), dep(d, term.get_manager()) {} | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     typedef vector<dependent_eq> dep_eq_vector; |     typedef vector<dependent_eq> dep_eq_vector; | ||||||
|  |  | ||||||
|  | @ -329,6 +329,7 @@ namespace euf { | ||||||
|         m_config.m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); |         m_config.m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); | ||||||
|         for (auto* ex : m_extract_plugins) |         for (auto* ex : m_extract_plugins) | ||||||
|             ex->updt_params(p); |             ex->updt_params(p); | ||||||
|  |         m_rewriter.updt_params(p); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solve_eqs::collect_param_descrs(param_descrs& r) { |     void solve_eqs::collect_param_descrs(param_descrs& r) { | ||||||
|  |  | ||||||
|  | @ -25,12 +25,15 @@ Author: | ||||||
| 
 | 
 | ||||||
| namespace bv { | namespace bv { | ||||||
| 
 | 
 | ||||||
|     sls::sls(ast_manager& m):  |     sls::sls(ast_manager& m, params_ref const& p):  | ||||||
|         m(m),  |         m(m),  | ||||||
|         bv(m), |         bv(m), | ||||||
|         m_terms(m), |         m_terms(m), | ||||||
|         m_eval(m) |         m_eval(m), | ||||||
|     {} |         m_engine(m, p) | ||||||
|  |     { | ||||||
|  |         updt_params(p); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     void sls::init() { |     void sls::init() { | ||||||
|         m_terms.init();  |         m_terms.init();  | ||||||
|  | @ -53,38 +56,96 @@ namespace bv { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         for (auto* t : m_terms.terms()) { |         for (auto* t : m_terms.terms()) { | ||||||
|             if (t && !re_eval_is_correct(t))  |             if (t && !m_eval.re_eval_is_correct(t))  | ||||||
|                 m_repair_roots.insert(t->get_id());             |                 m_repair_roots.insert(t->get_id());             | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     void sls::set_model() { | ||||||
|  |         if (!m_set_model) | ||||||
|  |             return; | ||||||
|  |         if (m_repair_roots.size() >= m_min_repair_size) | ||||||
|  |             return; | ||||||
|  |         m_min_repair_size = m_repair_roots.size(); | ||||||
|  |         IF_VERBOSE(2, verbose_stream() << "(sls-update-model :num-unsat " << m_min_repair_size << ")\n"); | ||||||
|  |         m_set_model(*get_model()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void sls::init_repair_goal(app* t) { |     void sls::init_repair_goal(app* t) { | ||||||
|         if (m.is_bool(t))  |         m_eval.init_eval(t); | ||||||
|             m_eval.set(t, m_eval.bval1(t));         |     } | ||||||
|         else if (bv.is_bv(t)) { | 
 | ||||||
|             auto& v = m_eval.wval(t); |     void sls::init_repair_candidates() { | ||||||
|             v.bits().copy_to(v.nw, v.eval); |         m_to_repair.reset(); | ||||||
|  |         ptr_vector<expr> todo; | ||||||
|  |         expr_fast_mark1 mark; | ||||||
|  |         for (auto index : m_repair_roots)  | ||||||
|  |             todo.push_back(m_terms.term(index)); | ||||||
|  |         for (unsigned i = 0; i < todo.size(); ++i) { | ||||||
|  |             expr* e = todo[i]; | ||||||
|  |             if (mark.is_marked(e)) | ||||||
|  |                 continue; | ||||||
|  |             mark.mark(e); | ||||||
|  |             if (!is_app(e)) | ||||||
|  |                 continue; | ||||||
|  |             for (expr* arg : *to_app(e)) | ||||||
|  |                 todo.push_back(arg); | ||||||
|  | 
 | ||||||
|  |             if (is_uninterp_const(e)) | ||||||
|  |                 m_to_repair.insert(e->get_id()); | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     void sls::reinit_eval() { |     void sls::reinit_eval() { | ||||||
|  |         init_repair_candidates(); | ||||||
|  | 
 | ||||||
|  |         if (m_to_repair.empty()) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         // refresh the best model so far to a callback
 | ||||||
|  |         set_model(); | ||||||
|  | 
 | ||||||
|  |         // add fresh units, if any
 | ||||||
|  |         bool new_assertion = false; | ||||||
|  |         while (m_get_unit) { | ||||||
|  |             auto e = m_get_unit(); | ||||||
|  |             if (!e) | ||||||
|  |                 break; | ||||||
|  |             new_assertion = true; | ||||||
|  |             assert_expr(e); | ||||||
|  |         } | ||||||
|  |         if (new_assertion)  | ||||||
|  |             init();         | ||||||
|  |             | ||||||
|         std::function<bool(expr*, unsigned)> eval = [&](expr* e, unsigned i) { |         std::function<bool(expr*, unsigned)> eval = [&](expr* e, unsigned i) { | ||||||
|             auto should_keep = [&]() { |             unsigned id = e->get_id(); | ||||||
|                 return m_rand() % 100 <= 92; |             bool keep = !m_to_repair.contains(id); | ||||||
|             }; |  | ||||||
|             if (m.is_bool(e)) { |             if (m.is_bool(e)) { | ||||||
|                 if (m_eval.is_fixed0(e) || should_keep()) |                 if (m_eval.is_fixed0(e) || keep) | ||||||
|                     return m_eval.bval0(e); |                     return m_eval.bval0(e); | ||||||
|  |                 if (m_engine_init) { | ||||||
|  |                     auto const& z = m_engine.get_value(e); | ||||||
|  |                     return rational(z).get_bit(0); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             else if (bv.is_bv(e)) { |             else if (bv.is_bv(e)) { | ||||||
|                 auto& w = m_eval.wval(e); |                 auto& w = m_eval.wval(e); | ||||||
|                 if (w.fixed.get(i) || should_keep()) |                 if (w.fixed.get(i) || keep) | ||||||
|                     return w.get_bit(i); |                     return w.get_bit(i); | ||||||
|  |                 if (m_engine_init) { | ||||||
|  |                     auto const& z = m_engine.get_value(e); | ||||||
|  |                     return rational(z).get_bit(i); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |              | ||||||
|             return m_rand() % 2 == 0; |             return m_rand() % 2 == 0; | ||||||
|         }; |         }; | ||||||
|         m_eval.init_eval(m_terms.assertions(), eval); |         m_eval.init_eval(m_terms.assertions(), eval); | ||||||
|         init_repair(); |         init_repair(); | ||||||
|  |         // m_engine_init = false;
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::pair<bool, app*> sls::next_to_repair() { |     std::pair<bool, app*> sls::next_to_repair() { | ||||||
|  | @ -109,7 +170,7 @@ namespace bv { | ||||||
|                 SASSERT(m_eval.bval0(e)); |                 SASSERT(m_eval.bval0(e)); | ||||||
|                 return { true, e }; |                 return { true, e }; | ||||||
|             } |             } | ||||||
|             if (!re_eval_is_correct(e)) { |             if (!m_eval.re_eval_is_correct(e)) { | ||||||
|                 init_repair_goal(e); |                 init_repair_goal(e); | ||||||
|                 return { true, e }; |                 return { true, e }; | ||||||
|             } |             } | ||||||
|  | @ -119,19 +180,17 @@ namespace bv { | ||||||
|         return { false, nullptr }; |         return { false, nullptr }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lbool sls::search() { |     lbool sls::search1() { | ||||||
|         // init and init_eval were invoked
 |         // init and init_eval were invoked
 | ||||||
|         unsigned n = 0; |         unsigned n = 0; | ||||||
|         for (; n++ < m_config.m_max_repairs && m.inc(); ) { |         for (; n < m_config.m_max_repairs && m.inc(); ++n) { | ||||||
|             auto [down, e] = next_to_repair(); |             auto [down, e] = next_to_repair(); | ||||||
|             if (!e) |             if (!e) | ||||||
|                 return l_true; |                 return l_true; | ||||||
| 
 | 
 | ||||||
| 
 |             IF_VERBOSE(20, trace_repair(down, e)); | ||||||
|             trace_repair(down, e); |  | ||||||
|              |              | ||||||
|             ++m_stats.m_moves; |             ++m_stats.m_moves; | ||||||
| 
 |  | ||||||
|             if (down)  |             if (down)  | ||||||
|                 try_repair_down(e);             |                 try_repair_down(e);             | ||||||
|             else |             else | ||||||
|  | @ -140,16 +199,35 @@ namespace bv { | ||||||
|         return l_undef; |         return l_undef; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     lbool sls::search2() { | ||||||
|  |         lbool res = l_undef; | ||||||
|  |         if (m_stats.m_restarts == 0) | ||||||
|  |             res = m_engine(), | ||||||
|  |             m_engine_init = true; | ||||||
|  |         else if (m_stats.m_restarts % 1000 == 0) | ||||||
|  |             res = m_engine.search_loop(), | ||||||
|  |             m_engine_init = true; | ||||||
|  |         if (res != l_undef)  | ||||||
|  |             m_engine_model = true;    | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     lbool sls::operator()() { |     lbool sls::operator()() { | ||||||
|         lbool res = l_undef; |         lbool res = l_undef; | ||||||
|         m_stats.reset(); |         m_stats.reset(); | ||||||
|         m_stats.m_restarts = 0; |         m_stats.m_restarts = 0; | ||||||
|  |         m_engine_model = false; | ||||||
|  |         m_engine_init = false; | ||||||
|  | 
 | ||||||
|         do { |         do { | ||||||
|             res = search(); |             res = search1(); | ||||||
|             if (res != l_undef) |             if (res != l_undef) | ||||||
|                 break; |                 break; | ||||||
|             trace(); |             trace(); | ||||||
|  |             //res = search2();
 | ||||||
|  |             if (res != l_undef) | ||||||
|  |                 break; | ||||||
|             reinit_eval(); |             reinit_eval(); | ||||||
|         }  |         }  | ||||||
|         while (m.inc() && m_stats.m_restarts++ < m_config.m_max_restarts); |         while (m.inc() && m_stats.m_restarts++ < m_config.m_max_restarts); | ||||||
|  | @ -158,93 +236,84 @@ namespace bv { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls::try_repair_down(app* e) { |     void sls::try_repair_down(app* e) { | ||||||
| 
 |  | ||||||
|         unsigned n = e->get_num_args(); |         unsigned n = e->get_num_args(); | ||||||
|         if (n == 0) { |         if (n == 0) { | ||||||
|             if (m.is_bool(e))  |             m_eval.commit_eval(e);            | ||||||
|                 m_eval.set(e, m_eval.bval1(e));                             |  | ||||||
|             else  |  | ||||||
|                 VERIFY(m_eval.wval(e).commit_eval()); |  | ||||||
|              |  | ||||||
|             for (auto p : m_terms.parents(e)) |             for (auto p : m_terms.parents(e)) | ||||||
|                 m_repair_up.insert(p->get_id()); |                 m_repair_up.insert(p->get_id()); | ||||||
|  |              | ||||||
|             return; |             return; | ||||||
|         }         |         }         | ||||||
| 
 | 
 | ||||||
|         unsigned s = m_rand(n); |         if (n == 2) { | ||||||
|         for (unsigned i = 0; i < n; ++i) { |             auto d1 = get_depth(e->get_arg(0)); | ||||||
|             auto j = (i + s) % n; |             auto d2 = get_depth(e->get_arg(1)); | ||||||
|             if (m_eval.try_repair(e, j)) { |             unsigned s = m_rand(d1 + d2 + 2); | ||||||
|                 set_repair_down(e->get_arg(j)); |             if (s <= d1 && m_eval.try_repair(e, 0)) { | ||||||
|  |                 set_repair_down(e->get_arg(0)); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if (m_eval.try_repair(e, 1)) { | ||||||
|  |                 set_repair_down(e->get_arg(1)); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if (m_eval.try_repair(e, 0)) { | ||||||
|  |                 set_repair_down(e->get_arg(0)); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         // search a new root / random walk to repair        
 |         else { | ||||||
|  |             unsigned s = m_rand(n); | ||||||
|  |             for (unsigned i = 0; i < n; ++i) { | ||||||
|  |                 auto j = (i + s) % n; | ||||||
|  |                 if (m_eval.try_repair(e, j)) { | ||||||
|  |                     set_repair_down(e->get_arg(j)); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         IF_VERBOSE(3, verbose_stream() << "init-repair " << mk_bounded_pp(e, m) << "\n"); | ||||||
|  |         // repair was not successful, so reset the state to find a different way to repair
 | ||||||
|  |         init_repair(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls::try_repair_up(app* e) {        |     void sls::try_repair_up(app* e) {        | ||||||
|          |          | ||||||
|         if (m_terms.is_assertion(e) || !m_eval.repair_up(e))  |         if (m_terms.is_assertion(e))  | ||||||
|             m_repair_roots.insert(e->get_id());     |             m_repair_roots.insert(e->get_id());     | ||||||
|  |         else if (!m_eval.repair_up(e)) { | ||||||
|  |             IF_VERBOSE(2, verbose_stream() << "repair-up "; trace_repair(true, e)); | ||||||
|  |             if (m_rand(10) != 0) { | ||||||
|  |                 m_eval.set_random(e);                 | ||||||
|  |                 m_repair_roots.insert(e->get_id()); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |                 init_repair(); | ||||||
|  |         } | ||||||
|         else { |         else { | ||||||
|             if (!eval_is_correct(e)) { |             if (!m_eval.eval_is_correct(e)) { | ||||||
|                 verbose_stream() << "incorrect eval #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; |                 verbose_stream() << "incorrect eval #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; | ||||||
|             } |             } | ||||||
|             SASSERT(eval_is_correct(e)); |             SASSERT(m_eval.eval_is_correct(e)); | ||||||
|             for (auto p : m_terms.parents(e)) |             for (auto p : m_terms.parents(e)) | ||||||
|                 m_repair_up.insert(p->get_id()); |                 m_repair_up.insert(p->get_id()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls::eval_is_correct(app* e) { |  | ||||||
|         if (!m_eval.can_eval1(e)) |  | ||||||
|             return false; |  | ||||||
|         if (m.is_bool(e)) |  | ||||||
|             return m_eval.bval0(e) == m_eval.bval1(e); |  | ||||||
|         if (bv.is_bv(e)) { |  | ||||||
|             auto const& v = m_eval.wval(e); |  | ||||||
|             return v.eval == v.bits(); |  | ||||||
|         } |  | ||||||
|         UNREACHABLE(); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     bool sls::re_eval_is_correct(app* e) { |  | ||||||
|         if (!m_eval.can_eval1(e)) |  | ||||||
|             return false; |  | ||||||
|         if (m.is_bool(e)) |  | ||||||
|             return m_eval.bval0(e) == m_eval.bval1(e); |  | ||||||
|         if (bv.is_bv(e)) { |  | ||||||
|             auto const& v = m_eval.eval(e); |  | ||||||
|             return v.eval == v.bits(); |  | ||||||
|         } |  | ||||||
|         UNREACHABLE(); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     model_ref sls::get_model() { |     model_ref sls::get_model() { | ||||||
|  |         if (m_engine_model) | ||||||
|  |             return m_engine.get_model(); | ||||||
|  | 
 | ||||||
|         model_ref mdl = alloc(model, m);          |         model_ref mdl = alloc(model, m);          | ||||||
|         auto& terms = m_eval.sort_assertions(m_terms.assertions()); |         auto& terms = m_eval.sort_assertions(m_terms.assertions()); | ||||||
|         for (expr* e : terms) { |         for (expr* e : terms) { | ||||||
|             if (!re_eval_is_correct(to_app(e))) { |  | ||||||
|                 verbose_stream() << "missed evaluation #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; |  | ||||||
|                 if (bv.is_bv(e)) { |  | ||||||
|                     auto const& v = m_eval.wval(e); |  | ||||||
|                     verbose_stream() << v << "\n" << v.eval << "\n"; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             if (!is_uninterp_const(e)) |             if (!is_uninterp_const(e)) | ||||||
|                 continue; |                 continue; | ||||||
| 
 |  | ||||||
|             auto f = to_app(e)->get_decl(); |             auto f = to_app(e)->get_decl(); | ||||||
|             if (m.is_bool(e)) |             auto v = m_eval.get_value(to_app(e)); | ||||||
|                 mdl->register_decl(f, m.mk_bool_val(m_eval.bval0(e))); |             if (v) | ||||||
|             else if (bv.is_bv(e)) { |                 mdl->register_decl(f, v); | ||||||
|                 auto const& v = m_eval.wval(e); |  | ||||||
|                 rational n = v.get_value(); |  | ||||||
|                 mdl->register_decl(f, bv.mk_numeral(n, v.bw)); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         terms.reset(); |         terms.reset(); | ||||||
|         return mdl; |         return mdl; | ||||||
|  | @ -260,10 +329,7 @@ namespace bv { | ||||||
|                 out << "u "; |                 out << "u "; | ||||||
|             if (m_repair_roots.contains(e->get_id())) |             if (m_repair_roots.contains(e->get_id())) | ||||||
|                 out << "r "; |                 out << "r "; | ||||||
|             if (bv.is_bv(e)) |             m_eval.display_value(out, e); | ||||||
|                 out << m_eval.wval(e); |  | ||||||
|             else if (m.is_bool(e)) |  | ||||||
|                 out << (m_eval.bval0(e)?"T":"F"); |  | ||||||
|             out << "\n"; |             out << "\n"; | ||||||
|         } |         } | ||||||
|         terms.reset(); |         terms.reset(); | ||||||
|  | @ -273,17 +339,20 @@ namespace bv { | ||||||
|     void sls::updt_params(params_ref const& _p) { |     void sls::updt_params(params_ref const& _p) { | ||||||
|         sls_params p(_p); |         sls_params p(_p); | ||||||
|         m_config.m_max_restarts = p.max_restarts(); |         m_config.m_max_restarts = p.max_restarts(); | ||||||
|  |         m_config.m_max_repairs = p.max_repairs(); | ||||||
|         m_rand.set_seed(p.random_seed()); |         m_rand.set_seed(p.random_seed()); | ||||||
|  |         m_terms.updt_params(_p); | ||||||
|  |         params_ref q = _p; | ||||||
|  |         q.set_uint("max_restarts", 10); | ||||||
|  |         m_engine.updt_params(q); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls::trace_repair(bool down, expr* e) { |     std::ostream& sls::trace_repair(bool down, expr* e) { | ||||||
|         IF_VERBOSE(20, |         verbose_stream() << (down ? "d #" : "u #") | ||||||
|             verbose_stream() << (down ? "d #" : "u #") |  | ||||||
|             << e->get_id() << ": " |             << e->get_id() << ": " | ||||||
|             << mk_bounded_pp(e, m, 1) << " "; |             << mk_bounded_pp(e, m, 1) << " "; | ||||||
|         if (bv.is_bv(e)) verbose_stream() << m_eval.wval(e) << " " << (m_eval.is_fixed0(e) ? "fixed " : " "); |         m_eval.display_value(verbose_stream(), e) << "\n"; | ||||||
|         if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; |         return verbose_stream(); | ||||||
|         verbose_stream() << "\n"); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls::trace() { |     void sls::trace() { | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ Author: | ||||||
| #include "ast/sls/sls_valuation.h" | #include "ast/sls/sls_valuation.h" | ||||||
| #include "ast/sls/bv_sls_terms.h" | #include "ast/sls/bv_sls_terms.h" | ||||||
| #include "ast/sls/bv_sls_eval.h" | #include "ast/sls/bv_sls_eval.h" | ||||||
|  | #include "ast/sls/sls_engine.h" | ||||||
| #include "ast/bv_decl_plugin.h" | #include "ast/bv_decl_plugin.h" | ||||||
| #include "model/model.h" | #include "model/model.h" | ||||||
| 
 | 
 | ||||||
|  | @ -49,33 +50,41 @@ namespace bv { | ||||||
|         ptr_vector<expr>    m_todo; |         ptr_vector<expr>    m_todo; | ||||||
|         random_gen          m_rand; |         random_gen          m_rand; | ||||||
|         config              m_config; |         config              m_config; | ||||||
|  |         sls_engine          m_engine; | ||||||
|  |         bool                m_engine_model = false; | ||||||
|  |         bool                m_engine_init = false; | ||||||
|  |         std::function<expr_ref()> m_get_unit; | ||||||
|  |         std::function<void(model& mdl)> m_set_model; | ||||||
|  |         unsigned            m_min_repair_size = UINT_MAX; | ||||||
|          |          | ||||||
|         std::pair<bool, app*> next_to_repair(); |         std::pair<bool, app*> next_to_repair(); | ||||||
|          |          | ||||||
|         bool eval_is_correct(app* e); |  | ||||||
|         bool re_eval_is_correct(app* e); |  | ||||||
|         void init_repair_goal(app* e); |         void init_repair_goal(app* e); | ||||||
|  |         void set_model(); | ||||||
|         void try_repair_down(app* e); |         void try_repair_down(app* e); | ||||||
|         void try_repair_up(app* e); |         void try_repair_up(app* e); | ||||||
|         void set_repair_down(expr* e) { m_repair_down = e->get_id(); } |         void set_repair_down(expr* e) { m_repair_down = e->get_id(); } | ||||||
| 
 | 
 | ||||||
|         lbool search(); |         lbool search1(); | ||||||
|  |         lbool search2(); | ||||||
|         void reinit_eval(); |         void reinit_eval(); | ||||||
|         void init_repair(); |         void init_repair(); | ||||||
|         void trace(); |         void trace(); | ||||||
|         void trace_repair(bool down, expr* e); |         std::ostream& trace_repair(bool down, expr* e); | ||||||
|  | 
 | ||||||
|  |         indexed_uint_set m_to_repair; | ||||||
|  |         void init_repair_candidates(); | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
|         sls(ast_manager& m); |         sls(ast_manager& m, params_ref const& p); | ||||||
|                  |                  | ||||||
|         /**
 |         /**
 | ||||||
|         * Add constraints |         * Add constraints | ||||||
|         */ |         */ | ||||||
|         void assert_expr(expr* e) { m_terms.assert_expr(e); } |         void assert_expr(expr* e) { m_terms.assert_expr(e); m_engine.assert_expr(e); } | ||||||
| 
 | 
 | ||||||
|         /*
 |         /*
 | ||||||
|         * Invoke init after all expressions are asserted.  |         * Invoke init after all expressions are asserted.  | ||||||
|         * No other expressions can be asserted after init. |  | ||||||
|         */ |         */ | ||||||
|         void init(); |         void init(); | ||||||
| 
 | 
 | ||||||
|  | @ -85,16 +94,26 @@ namespace bv { | ||||||
|         */ |         */ | ||||||
|         void init_eval(std::function<bool(expr*, unsigned)>& eval); |         void init_eval(std::function<bool(expr*, unsigned)>& eval); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |         * add callback to retrieve new units | ||||||
|  |         */ | ||||||
|  |         void init_unit(std::function<expr_ref()> get_unit) { m_get_unit = get_unit; } | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |         * Add callback to set model | ||||||
|  |         */ | ||||||
|  |         void set_model(std::function<void(model& mdl)> f) { m_set_model = f; } | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|         * Run (bounded) local search to find feasible assignments. |         * Run (bounded) local search to find feasible assignments. | ||||||
|         */ |         */ | ||||||
|         lbool operator()(); |         lbool operator()(); | ||||||
| 
 | 
 | ||||||
|         void updt_params(params_ref const& p); |         void updt_params(params_ref const& p); | ||||||
|         void collect_statistics(statistics & st) const { m_stats.collect_statistics(st); } |         void collect_statistics(statistics& st) const { m_stats.collect_statistics(st); m_engine.collect_statistics(st); } | ||||||
|         void reset_statistics() { m_stats.reset(); } |         void reset_statistics() { m_stats.reset(); m_engine.reset_statistics(); } | ||||||
| 
 | 
 | ||||||
|         sls_stats const& get_stats() const { return m_stats; } |         unsigned get_num_moves() { return m_stats.m_moves + m_engine.get_stats().m_moves; } | ||||||
| 
 | 
 | ||||||
|         std::ostream& display(std::ostream& out); |         std::ostream& display(std::ostream& out); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,8 +24,8 @@ namespace bv { | ||||||
|     {}    |     {}    | ||||||
| 
 | 
 | ||||||
|     void sls_eval::init_eval(expr_ref_vector const& es, std::function<bool(expr*, unsigned)> const& eval) { |     void sls_eval::init_eval(expr_ref_vector const& es, std::function<bool(expr*, unsigned)> const& eval) { | ||||||
|         sort_assertions(es); |         auto& terms = sort_assertions(es); | ||||||
|         for (expr* e : m_todo) { |         for (expr* e : terms) { | ||||||
|             if (!is_app(e)) |             if (!is_app(e)) | ||||||
|                 continue; |                 continue; | ||||||
|             app* a = to_app(e); |             app* a = to_app(e); | ||||||
|  | @ -49,7 +49,7 @@ namespace bv { | ||||||
|                 TRACE("sls", tout << "Unhandled expression " << mk_pp(e, m) << "\n"); |                 TRACE("sls", tout << "Unhandled expression " << mk_pp(e, m) << "\n"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         m_todo.reset(); |         terms.reset(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -84,10 +84,13 @@ namespace bv { | ||||||
|             return false; |             return false; | ||||||
|         auto v = alloc_valuation(e); |         auto v = alloc_valuation(e); | ||||||
|         m_values.set(e->get_id(), v); |         m_values.set(e->get_id(), v); | ||||||
|         if (bv.is_sign_ext(e)) { |         expr* x, * y; | ||||||
|             unsigned p = e->get_parameter(0).get_int(); |         rational val; | ||||||
|             v->set_signed(p); |         if (bv.is_sign_ext(e))           | ||||||
|         } |             v->set_signed(e->get_parameter(0).get_int());         | ||||||
|  |         else if (bv.is_bv_ashr(e, x, y) && bv.is_numeral(y, val) &&  | ||||||
|  |             val.is_unsigned() && val.get_unsigned() <= bv.get_bv_size(e))  | ||||||
|  |             v->set_signed(val.get_unsigned());         | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -911,26 +914,25 @@ namespace bv { | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_eq(bool is_true, bvval& a, bvval const& b) { |     bool sls_eval::try_repair_eq(bool is_true, bvval& a, bvval const& b) { | ||||||
|         if (is_true) { |         if (is_true) { | ||||||
|             if (m_rand() % 20 != 0)  |             if (m_rand(20) != 0)  | ||||||
|                 if (a.try_set(b.bits())) |                 if (a.try_set(b.bits())) | ||||||
|                     return true; |                     return true; | ||||||
|              |              | ||||||
|             a.get_variant(m_tmp, m_rand); |             return a.set_random(m_rand); | ||||||
|             return a.set_repair(random_bool(), m_tmp); |  | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             bool try_above = m_rand() % 2 == 0; |             bool try_above = m_rand(2) == 0; | ||||||
|             if (try_above) { |             if (try_above) { | ||||||
|                 a.set_add(m_tmp, b.bits(), m_one); |                 a.set_add(m_tmp, b.bits(), m_one); | ||||||
|                 if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) |                 if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp,  m_rand)) | ||||||
|                     return true; |                     return true; | ||||||
|             } |             } | ||||||
|             a.set_sub(m_tmp, b.bits(), m_one); |             a.set_sub(m_tmp, b.bits(), m_one); | ||||||
|             if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_tmp2, m_rand)) |             if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_rand)) | ||||||
|                 return true; |                 return true; | ||||||
|             if (!try_above) { |             if (!try_above) { | ||||||
|                 a.set_add(m_tmp, b.bits(), m_one); |                 a.set_add(m_tmp, b.bits(), m_one); | ||||||
|                 if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) |                 if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_rand)) | ||||||
|                     return true; |                     return true; | ||||||
|             } |             } | ||||||
|             return false; |             return false; | ||||||
|  | @ -1005,7 +1007,6 @@ namespace bv { | ||||||
|     bool sls_eval::try_repair_bxor(bvect const& e, bvval& a, bvval const& b) { |     bool sls_eval::try_repair_bxor(bvect const& e, bvval& a, bvval const& b) { | ||||||
|         for (unsigned i = 0; i < a.nw; ++i) |         for (unsigned i = 0; i < a.nw; ++i) | ||||||
|             m_tmp[i] = e[i] ^ b.bits()[i]; |             m_tmp[i] = e[i] ^ b.bits()[i]; | ||||||
|         a.clear_overflow_bits(m_tmp); |  | ||||||
|         return a.set_repair(random_bool(), m_tmp); |         return a.set_repair(random_bool(), m_tmp); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1015,17 +1016,16 @@ namespace bv { | ||||||
|     // If this fails, set a to a random value
 |     // If this fails, set a to a random value
 | ||||||
|     // 
 |     // 
 | ||||||
|     bool sls_eval::try_repair_add(bvect const& e, bvval& a, bvval const& b) { |     bool sls_eval::try_repair_add(bvect const& e, bvval& a, bvval const& b) { | ||||||
|         if (m_rand() % 20 != 0) { |         if (m_rand(20) != 0) { | ||||||
|             a.set_sub(m_tmp, e, b.bits()); |             a.set_sub(m_tmp, e, b.bits()); | ||||||
|             if (a.try_set(m_tmp)) |             if (a.try_set(m_tmp)) | ||||||
|                 return true; |                 return true; | ||||||
|         } |         } | ||||||
|         a.get_variant(m_tmp, m_rand); |         return a.set_random(m_rand);         | ||||||
|         return a.set_repair(random_bool(), m_tmp);           |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_sub(bvect const& e, bvval& a, bvval & b, unsigned i) { |     bool sls_eval::try_repair_sub(bvect const& e, bvval& a, bvval & b, unsigned i) { | ||||||
|         if (m_rand() % 20 != 0) { |         if (m_rand(20) != 0) { | ||||||
|             if (i == 0)  |             if (i == 0)  | ||||||
|                 // e = a - b -> a := e + b
 |                 // e = a - b -> a := e + b
 | ||||||
|                 a.set_add(m_tmp, e, b.bits());         |                 a.set_add(m_tmp, e, b.bits());         | ||||||
|  | @ -1036,8 +1036,7 @@ namespace bv { | ||||||
|                 return true; |                 return true; | ||||||
|         } |         } | ||||||
|         // fall back to a random value
 |         // fall back to a random value
 | ||||||
|         a.get_variant(m_tmp, m_rand); |         return a.set_random(m_rand);         | ||||||
|         return a.set_repair(random_bool(), m_tmp); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -1055,15 +1054,11 @@ namespace bv { | ||||||
|             return a.set_repair(random_bool(), m_tmp); |             return a.set_repair(random_bool(), m_tmp); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (b.is_zero()) { |         if (b.is_zero())  | ||||||
|             a.get_variant(m_tmp, m_rand); |             return a.set_random(m_rand);           | ||||||
|             return a.set_repair(random_bool(), m_tmp);             |  | ||||||
|         }       |  | ||||||
|          |          | ||||||
|         if (m_rand() % 20 == 0) { |         if (m_rand(20) == 0)  | ||||||
|             a.get_variant(m_tmp, m_rand); |             return a.set_random(m_rand); | ||||||
|             return a.set_repair(random_bool(), m_tmp);             |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
| #if 0 | #if 0 | ||||||
|         verbose_stream() << "solve for " << e << "\n"; |         verbose_stream() << "solve for " << e << "\n"; | ||||||
|  | @ -1093,7 +1088,7 @@ namespace bv { | ||||||
|             b.shift_right(y, parity_b); |             b.shift_right(y, parity_b); | ||||||
| #if 0 | #if 0 | ||||||
|             for (unsigned i = parity_b; i < b.bw; ++i) |             for (unsigned i = parity_b; i < b.bw; ++i) | ||||||
|                 y.set(i, m_rand() % 2 == 0); |                 y.set(i, m_rand(2) == 0); | ||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -1148,8 +1143,7 @@ namespace bv { | ||||||
|         if (a.set_repair(random_bool(), m_tmp)) |         if (a.set_repair(random_bool(), m_tmp)) | ||||||
|             return true; |             return true; | ||||||
| 
 | 
 | ||||||
|         a.get_variant(m_tmp, m_rand); |         return a.set_random(m_rand); | ||||||
|         return a.set_repair(random_bool(), m_tmp); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_bnot(bvect const& e, bvval& a) { |     bool sls_eval::try_repair_bnot(bvect const& e, bvval& a) { | ||||||
|  | @ -1233,16 +1227,16 @@ namespace bv { | ||||||
|     bool sls_eval::try_repair_sle(bvval& a, bvect const& b, bvect const& p2) { |     bool sls_eval::try_repair_sle(bvval& a, bvect const& b, bvect const& p2) { | ||||||
|         bool r = false; |         bool r = false; | ||||||
|         if (b < p2) { |         if (b < p2) { | ||||||
|             bool coin = m_rand() % 2 == 0; |             bool coin = m_rand(2) == 0; | ||||||
|             if (coin) |             if (coin) | ||||||
|                 r = a.set_random_at_least(p2, m_tmp3, m_rand); |                 r = a.set_random_at_least(p2, m_rand); | ||||||
|             if (!r) |             if (!r) | ||||||
|                 r = a.set_random_at_most(b, m_tmp3, m_rand); |                 r = a.set_random_at_most(b, m_rand); | ||||||
|             if (!coin && !r) |             if (!coin && !r) | ||||||
|                 r = a.set_random_at_least(p2, m_tmp3, m_rand); |                 r = a.set_random_at_least(p2, m_rand); | ||||||
|         } |         } | ||||||
|         else  |         else  | ||||||
|             r = a.set_random_in_range(p2, b, m_tmp3, m_rand); |             r = a.set_random_in_range(p2, b, m_rand); | ||||||
|         return r; |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1262,16 +1256,16 @@ namespace bv { | ||||||
|         bool r = false; |         bool r = false; | ||||||
|         if (p2 < b)  |         if (p2 < b)  | ||||||
|             // random b <= x < p2 
 |             // random b <= x < p2 
 | ||||||
|             r = a.set_random_in_range(b, p2_1, m_tmp3, m_rand);         |             r = a.set_random_in_range(b, p2_1, m_rand);         | ||||||
|         else { |         else { | ||||||
|             // random b <= x or x < p2
 |             // random b <= x or x < p2
 | ||||||
|             bool coin = m_rand() % 2 == 0; |             bool coin = m_rand(2) == 0; | ||||||
|             if (coin) |             if (coin) | ||||||
|                 r = a.set_random_at_most(p2_1, m_tmp3, m_rand); |                 r = a.set_random_at_most(p2_1,m_rand); | ||||||
|             if (!r) |             if (!r) | ||||||
|                 r = a.set_random_at_least(b, m_tmp3, m_rand); |                 r = a.set_random_at_least(b,  m_rand); | ||||||
|             if (!r && !coin) |             if (!r && !coin) | ||||||
|                 r = a.set_random_at_most(p2_1, m_tmp3, m_rand); |                 r = a.set_random_at_most(p2_1,  m_rand); | ||||||
|         } |         } | ||||||
|         p2_1.set_bw(0); |         p2_1.set_bw(0); | ||||||
|         return r; |         return r; | ||||||
|  | @ -1287,28 +1281,28 @@ namespace bv { | ||||||
|     bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { |     bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { | ||||||
|         if (e) { |         if (e) { | ||||||
|             // a <= t
 |             // a <= t
 | ||||||
|             return a.set_random_at_most(b.bits(), m_tmp, m_rand); |             return a.set_random_at_most(b.bits(),  m_rand); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             // a > t
 |             // a > t
 | ||||||
|             a.set_add(m_tmp, b.bits(), m_one); |             a.set_add(m_tmp, b.bits(), m_one); | ||||||
|             if (a.is_zero(m_tmp)) |             if (a.is_zero(m_tmp)) | ||||||
|                 return false;    |                 return false;    | ||||||
|             return a.set_random_at_least(m_tmp, m_tmp2, m_rand); |             return a.set_random_at_least(m_tmp, m_rand); | ||||||
|         }            |         }            | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { |     bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { | ||||||
|         if (e) { |         if (e) { | ||||||
|             // a >= t
 |             // a >= t
 | ||||||
|             return a.set_random_at_least(b.bits(), m_tmp, m_rand); |             return a.set_random_at_least(b.bits(), m_rand); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             // a < t
 |             // a < t
 | ||||||
|             if (b.is_zero()) |             if (b.is_zero()) | ||||||
|                 return false; |                 return false; | ||||||
|             a.set_sub(m_tmp, b.bits(), m_one); |             a.set_sub(m_tmp, b.bits(), m_one); | ||||||
|             return a.set_random_at_most(m_tmp, m_tmp2, m_rand); |             return a.set_random_at_most(m_tmp, m_rand); | ||||||
|         }     |         }     | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1349,40 +1343,260 @@ namespace bv { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_ashr(bvect const& e, bvval & a, bvval& b, unsigned i) {        |     bool sls_eval::try_repair_ashr(bvect const& e, bvval & a, bvval& b, unsigned i) {        | ||||||
|         if (i == 0) { |             if (i == 0) | ||||||
|             unsigned sh = b.to_nat(b.bw); |                 return try_repair_ashr0(e, a, b); | ||||||
|             if (sh == 0) |             else | ||||||
|                 return a.try_set(e); |                 return try_repair_ashr1(e, a, b); | ||||||
|             else if (sh >= b.bw) { |  | ||||||
|                 if (e.get(a.bw - 1))  |  | ||||||
|                     return a.try_set_bit(a.bw - 1, true);                 |  | ||||||
|                 else  |  | ||||||
|                     return a.try_set_bit(a.bw - 1, false); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 // e = a >> sh
 |  | ||||||
|                 // a[bw-1:sh] = e[bw-sh-1:0]
 |  | ||||||
|                 // a[sh-1:0] = a[sh-1:0]                
 |  | ||||||
|                 // ignore sign
 |  | ||||||
|                 for (unsigned i = sh; i < a.bw; ++i) |  | ||||||
|                     m_tmp.set(i, e.get(i - sh)); |  | ||||||
|                 for (unsigned i = 0; i < sh; ++i) |  | ||||||
|                     m_tmp.set(i, a.get_bit(i)); |  | ||||||
|                 a.clear_overflow_bits(m_tmp); |  | ||||||
|                 return a.try_set(m_tmp); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             // NB. blind sub-range of possible values for b
 |  | ||||||
|             SASSERT(i == 1); |  | ||||||
|             unsigned sh = m_rand(a.bw + 1); |  | ||||||
|             b.set(m_tmp, sh); |  | ||||||
|             return b.try_set(m_tmp); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i) { |     bool sls_eval::try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i) { | ||||||
|         return try_repair_ashr(e, a, b, i); |         if (i == 0) | ||||||
|  |             return try_repair_lshr0(e, a, b); | ||||||
|  |         else | ||||||
|  |             return try_repair_lshr1(e, a, b); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |     * strong:  | ||||||
|  |     * - e = (e << b) >> b -> a := e << b, upper b bits set random | ||||||
|  |     * weak: | ||||||
|  |     *   - e = 0 -> a := random  | ||||||
|  |     *   - e > 0 -> a := random with msb(a) >= msb(e) | ||||||
|  |     */ | ||||||
|  |     bool sls_eval::try_repair_lshr0(bvect const& e, bvval& a, bvval const& b) { | ||||||
|  |          | ||||||
|  |         auto& t = m_tmp; | ||||||
|  |         // t := e << b
 | ||||||
|  |         // t := t >> b
 | ||||||
|  |         t.set_shift_left(e, b.bits()); | ||||||
|  |         t.set_shift_right(t, b.bits()); | ||||||
|  |         bool use_strong = m_rand(10) != 0; | ||||||
|  |         if (t == e && use_strong) { | ||||||
|  |             t.set_shift_left(e, b.bits()); | ||||||
|  |             unsigned n = b.bits().to_nat(e.bw); | ||||||
|  |             for (unsigned i = e.bw; i-- > e.bw - n;)  | ||||||
|  |                 t.set(i, a.get_bit(i));  | ||||||
|  |             if (a.set_repair(random_bool(), t)) | ||||||
|  |                 return true;                       | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         unsigned sh = b.to_nat(b.bw); | ||||||
|  |         if (m_rand(20) != 0) { | ||||||
|  |             if (sh == 0 && a.try_set(e)) | ||||||
|  |                 return true; | ||||||
|  |             else if (sh >= b.bw) | ||||||
|  |                 return true; | ||||||
|  |             else if (sh < b.bw && m_rand(20) != 0) { | ||||||
|  |                 // e = a >> sh
 | ||||||
|  |                 // a[bw-1:sh] = e[bw-sh-1:0]
 | ||||||
|  |                 // a[sh-1:0] = a[sh-1:0]                
 | ||||||
|  |                 for (unsigned i = sh; i < a.bw; ++i) | ||||||
|  |                     t.set(i, e.get(i - sh)); | ||||||
|  |                 for (unsigned i = 0; i < sh; ++i) | ||||||
|  |                     t.set(i, a.get_bit(i)); | ||||||
|  |                 a.clear_overflow_bits(t); | ||||||
|  |                 if (a.try_set(t)) | ||||||
|  |                     return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         //bool r = try_repair_ashr(e, a, const_cast<bvval&>(b), 0);
 | ||||||
|  |         //verbose_stream() << "repair lshr0 " << e << " b: " << b << " a: " << a << "\n";
 | ||||||
|  |         //return r;
 | ||||||
|  | 
 | ||||||
|  |         a.get_variant(t, m_rand); | ||||||
|  |          | ||||||
|  |         unsigned msb = a.msb(e); | ||||||
|  |         if (msb > a.msb(t)) { | ||||||
|  |             unsigned num_flex = 0; | ||||||
|  |             for (unsigned i = e.bw; i-- >= msb;)  | ||||||
|  |                 if (!a.fixed.get(i)) | ||||||
|  |                     ++num_flex; | ||||||
|  |             if (num_flex == 0) | ||||||
|  |                 return false; | ||||||
|  |             unsigned n = m_rand(num_flex); | ||||||
|  |             for (unsigned i = e.bw; i-- >= msb;) { | ||||||
|  |                 if (!a.fixed.get(i)) { | ||||||
|  |                     if (n == 0) { | ||||||
|  |                         t.set(i, true); | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     else | ||||||
|  |                         n--; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return a.set_repair(random_bool(), t); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |     * strong: | ||||||
|  |     * - clz(a) <= clz(e), e = 0 or (a >> (clz(e) - clz(a)) = e | ||||||
|  |     * - e = 0 and a = 0:  b := random | ||||||
|  |     * - e = 0 and a != 0: b := random, such that shift <= b  | ||||||
|  |     * - e != 0:           b := shift | ||||||
|  |     * where shift := clz(e) - clz(a) | ||||||
|  |     *  | ||||||
|  |     * weak: | ||||||
|  |     * - e = 0:  b := random | ||||||
|  |     * - e > 0:  b := random >= clz(e) | ||||||
|  |     */ | ||||||
|  |     bool sls_eval::try_repair_lshr1(bvect const& e, bvval const& a, bvval& b) { | ||||||
|  | 
 | ||||||
|  |         auto& t = m_tmp; | ||||||
|  |         auto clza = a.clz(a.bits()); | ||||||
|  |         auto clze = a.clz(e); | ||||||
|  |         t.set_bw(a.bw); | ||||||
|  | 
 | ||||||
|  |         // strong
 | ||||||
|  |         if (m_rand(10) != 0 && clza <= clze && (a.is_zero(e) || t.set_shift_right(a.bits(), clze - clza) == e)) { | ||||||
|  |             if (a.is_zero(e) && a.is_zero())  | ||||||
|  |                 return true;             | ||||||
|  |             unsigned shift = clze - clza; | ||||||
|  |             if (a.is_zero(e))  | ||||||
|  |                 shift = m_rand(a.bw + 1 - shift) + shift;             | ||||||
|  |              | ||||||
|  |             b.set(t, shift); | ||||||
|  |             if (b.try_set(t)) | ||||||
|  |                 return true;             | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // no change
 | ||||||
|  |         if (m_rand(10) != 0) { | ||||||
|  |             if (a.is_zero(e)) | ||||||
|  |                 return true; | ||||||
|  |             if (b.bits() <= clze) | ||||||
|  |                 return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // weak
 | ||||||
|  |         b.get_variant(t, m_rand); | ||||||
|  |         if (a.is_zero(e))              | ||||||
|  |             return b.set_repair(random_bool(), t);         | ||||||
|  |         else { | ||||||
|  |             for (unsigned i = 0; i < 4; ++i) { | ||||||
|  |                 for (unsigned i = a.bw; !(t <= clze) && i-- > 0; ) | ||||||
|  |                     if (!b.fixed.get(i)) | ||||||
|  |                         t.set(i, false); | ||||||
|  |                 if (t <= clze && b.set_repair(random_bool(), t)) | ||||||
|  |                     return true;                 | ||||||
|  |                 b.get_variant(t, m_rand); | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         }         | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |     * strong: | ||||||
|  |     *   b  < |b| => (e << b) >>a b = e)  | ||||||
|  |     *   b >= |b| => (e = ones || e = 0) | ||||||
|  |     * - if b  < |b|: a := e << b | ||||||
|  |     * - if b >= |b|: a[bw-1] := e = ones | ||||||
|  |     * weak: | ||||||
|  |     *    | ||||||
|  |     */ | ||||||
|  |     bool sls_eval::try_repair_ashr0(bvect const& e, bvval& a, bvval const& b) { | ||||||
|  |         auto& t = m_tmp; | ||||||
|  |         t.set_bw(b.bw); | ||||||
|  |         auto n = b.msb(b.bits()); | ||||||
|  |         bool use_strong = m_rand(20) != 0; | ||||||
|  |         if (use_strong && n < b.bw) { | ||||||
|  |             t.set_shift_left(e, b.bits()); | ||||||
|  |             bool sign = t.get(b.bw-1); | ||||||
|  |             t.set_shift_right(t, b.bits()); | ||||||
|  |             if (sign) { | ||||||
|  |                 for (unsigned i = b.bw; i-- > b.bw - n; ) | ||||||
|  |                     t.set(i, true); | ||||||
|  |             }             | ||||||
|  |             use_strong &= t == e; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             use_strong &= a.is_zero(e) || a.is_ones(e); | ||||||
|  |         } | ||||||
|  |         if (use_strong) { | ||||||
|  |             if (n < b.bw) { | ||||||
|  |                 t.set_shift_left(e, b.bits()); | ||||||
|  |                 for (unsigned i = 0; i < n; ++i) | ||||||
|  |                     t.set(i, a.get_bit(i)); | ||||||
|  |             } | ||||||
|  |             else {                 | ||||||
|  |                 for (unsigned i = 0; i < b.nw; ++i) | ||||||
|  |                     t[i] = a.bits()[i]; | ||||||
|  |                 t.set(b.bw - 1, a.is_ones(e)); | ||||||
|  |             }    | ||||||
|  |             if (a.set_repair(random_bool(), t)) | ||||||
|  |                 return true; | ||||||
|  |         } | ||||||
|  |         if (m_rand(10) != 0) { | ||||||
|  |             if (n < b.bw) { | ||||||
|  |                 t.set_shift_left(e, b.bits()); | ||||||
|  |                 for (unsigned i = 0; i < n; ++i) | ||||||
|  |                     t.set(i, random_bool()); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 a.get_variant(t, m_rand); | ||||||
|  |                 t.set(b.bw - 1, a.is_ones(e)); | ||||||
|  |             } | ||||||
|  |             if (a.set_repair(random_bool(), t)) | ||||||
|  |                 return true; | ||||||
|  |         }             | ||||||
|  |         return a.set_random(m_rand); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |     * strong: | ||||||
|  |     * - clz(a) <= clz(e), e = 0 or (a >>a (clz(e) - clz(a)) = e | ||||||
|  |     * - e = 0 and a = 0:  b := random | ||||||
|  |     * - e = 0 and a != 0: b := random, such that shift <= b  | ||||||
|  |     * - e != 0:           b := shift | ||||||
|  |     * where shift := clz(e) - clz(a) | ||||||
|  |     *  | ||||||
|  |     * weak: | ||||||
|  |     * - e = 0:  b := random | ||||||
|  |     * - e > 0:  b := random >= clz(e) | ||||||
|  |     */ | ||||||
|  | 
 | ||||||
|  |     bool sls_eval::try_repair_ashr1(bvect const& e, bvval const& a, bvval& b) { | ||||||
|  | 
 | ||||||
|  |         auto& t = m_tmp; | ||||||
|  |         auto clza = a.clz(a.bits()); | ||||||
|  |         auto clze = a.clz(e); | ||||||
|  |         t.set_bw(a.bw); | ||||||
|  | 
 | ||||||
|  |         // strong unsigned
 | ||||||
|  |         if (!a.get_bit(a.bw - 1) && m_rand(10) != 0 && clza <= clze && (a.is_zero(e) || t.set_shift_right(a.bits(), clze - clza) == e)) { | ||||||
|  |             if (a.is_zero(e) && a.is_zero()) | ||||||
|  |                 return true; | ||||||
|  |             unsigned shift = clze - clza; | ||||||
|  |             if (a.is_zero(e)) | ||||||
|  |                 shift = m_rand(a.bw + 1 - shift) + shift; | ||||||
|  | 
 | ||||||
|  |             b.set(t, shift); | ||||||
|  |             if (b.try_set(t)) | ||||||
|  |                 return true; | ||||||
|  |         } | ||||||
|  |         // strong signed
 | ||||||
|  |         if (a.get_bit(a.bw - 1) && m_rand(10) != 0 && clza >= clze) { | ||||||
|  |             t.set_shift_right(a.bits(), clza - clze); | ||||||
|  |             for (unsigned i = a.bw; i-- > a.bw - clza + clze; ) | ||||||
|  |                 t.set(i, true); | ||||||
|  |             if (e == t) { | ||||||
|  |                 if (a.is_zero(e) && a.is_zero()) | ||||||
|  |                     return true; | ||||||
|  |                 unsigned shift = clze - clza; | ||||||
|  |                 if (a.is_zero(e)) | ||||||
|  |                     shift = m_rand(a.bw + 1 - shift) + shift; | ||||||
|  | 
 | ||||||
|  |                 b.set(t, shift); | ||||||
|  |                 if (b.try_set(t)) | ||||||
|  |                     return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // weak
 | ||||||
|  |         b.get_variant(t, m_rand); | ||||||
|  |         return b.set_repair(random_bool(), t); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_eval::try_repair_comp(bvect const& e, bvval& a, bvval& b, unsigned i) { |     bool sls_eval::try_repair_comp(bvect const& e, bvval& a, bvval& b, unsigned i) { | ||||||
|  | @ -1425,16 +1639,12 @@ namespace bv { | ||||||
|                 m_tmp2.set(b.msb(m_tmp2), false); |                 m_tmp2.set(b.msb(m_tmp2), false); | ||||||
|             while (a.set_add(m_tmp3, m_tmp, m_tmp2))  |             while (a.set_add(m_tmp3, m_tmp, m_tmp2))  | ||||||
|                 m_tmp2.set(b.msb(m_tmp2), false);        |                 m_tmp2.set(b.msb(m_tmp2), false);        | ||||||
|             a.clear_overflow_bits(m_tmp3); |  | ||||||
|             return a.set_repair(true, m_tmp3); |             return a.set_repair(true, m_tmp3); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             if (a.is_one(e) && a.is_zero()) { |             if (a.is_one(e) && a.is_zero())  | ||||||
|                 for (unsigned i = 0; i < a.nw; ++i) |                 return b.set_random(m_rand);               | ||||||
|                     m_tmp[i] = random_bits(); |              | ||||||
|                 a.clear_overflow_bits(m_tmp); |  | ||||||
|                 return b.set_repair(true, m_tmp);                 |  | ||||||
|             } |  | ||||||
|             if (a.is_one(e)) { |             if (a.is_one(e)) { | ||||||
|                 a.set(m_tmp, a.bits()); |                 a.set(m_tmp, a.bits()); | ||||||
|                 return b.set_repair(true, m_tmp); |                 return b.set_repair(true, m_tmp); | ||||||
|  | @ -1506,7 +1716,6 @@ namespace bv { | ||||||
|                 m_tmp[i] = random_bits(); |                 m_tmp[i] = random_bits(); | ||||||
|             a.set_sub(m_tmp2, a.bits(), e); |             a.set_sub(m_tmp2, a.bits(), e); | ||||||
|             set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4); |             set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4); | ||||||
|             a.clear_overflow_bits(m_tmp3); |  | ||||||
|             return b.set_repair(random_bool(), m_tmp3); |             return b.set_repair(random_bool(), m_tmp3); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -1631,7 +1840,6 @@ namespace bv { | ||||||
|             b.clear_overflow_bits(m_tmp); |             b.clear_overflow_bits(m_tmp); | ||||||
|             r = b.try_set(m_tmp); |             r = b.try_set(m_tmp); | ||||||
|         }        |         }        | ||||||
|         //verbose_stream() << e << " := " << a << " " << b << "\n";
 |  | ||||||
|         return r; |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1641,15 +1849,15 @@ namespace bv { | ||||||
|     // set a outside of [hi:lo] to random values with preference to 0 or 1 bits
 |     // set a outside of [hi:lo] to random values with preference to 0 or 1 bits
 | ||||||
|     // 
 |     // 
 | ||||||
|     bool sls_eval::try_repair_extract(bvect const& e, bvval& a, unsigned lo) { |     bool sls_eval::try_repair_extract(bvect const& e, bvval& a, unsigned lo) { | ||||||
|         if (m_rand() % m_config.m_prob_randomize_extract <= 100) { |         if (m_rand(m_config.m_prob_randomize_extract)  <= 100) { | ||||||
|             a.get_variant(m_tmp, m_rand); |             a.get_variant(m_tmp, m_rand); | ||||||
|             if (0 == (m_rand() % 2)) { |             if (0 == (m_rand(2))) { | ||||||
|                 auto bit = 0 == (m_rand() % 2); |                 auto bit = 0 == (m_rand(2)); | ||||||
|                 if (!a.try_set_range(m_tmp, 0, lo, bit)) |                 if (!a.try_set_range(m_tmp, 0, lo, bit)) | ||||||
|                     a.try_set_range(m_tmp, 0, lo, !bit); |                     a.try_set_range(m_tmp, 0, lo, !bit); | ||||||
|             } |             } | ||||||
|             if (0 == (m_rand() % 2)) { |             if (0 == (m_rand(2))) { | ||||||
|                 auto bit = 0 == (m_rand() % 2); |                 auto bit = 0 == (m_rand(2)); | ||||||
|                 if (!a.try_set_range(m_tmp, lo + e.bw, a.bw, bit)) |                 if (!a.try_set_range(m_tmp, lo + e.bw, a.bw, bit)) | ||||||
|                     a.try_set_range(m_tmp, lo + e.bw, a.bw, !bit); |                     a.try_set_range(m_tmp, lo + e.bw, a.bw, !bit); | ||||||
|             } |             } | ||||||
|  | @ -1660,10 +1868,7 @@ namespace bv { | ||||||
|             m_tmp.set(i + lo, e.get(i)); |             m_tmp.set(i + lo, e.get(i)); | ||||||
|         if (a.try_set(m_tmp)) |         if (a.try_set(m_tmp)) | ||||||
|             return true; |             return true; | ||||||
|         a.get_variant(m_tmp, m_rand);        |         return a.set_random(m_rand); | ||||||
|         bool res = a.set_repair(random_bool(), m_tmp); |  | ||||||
|         // verbose_stream() << "try set " << res << " " << m_tmp[0] << " " << a << "\n";
 |  | ||||||
|         return res; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw, |     void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw, | ||||||
|  | @ -1698,7 +1903,7 @@ namespace bv { | ||||||
|         } |         } | ||||||
|         if (bv.is_bv(e)) { |         if (bv.is_bv(e)) { | ||||||
|             auto& v = eval(to_app(e)); |             auto& v = eval(to_app(e)); | ||||||
|             // verbose_stream() << "committing: " << v << "\n";
 |              | ||||||
|             for (unsigned i = 0; i < v.nw; ++i) |             for (unsigned i = 0; i < v.nw; ++i) | ||||||
|                 if (0 != (v.fixed[i] & (v.bits()[i] ^ v.eval[i]))) { |                 if (0 != (v.fixed[i] & (v.bits()[i] ^ v.eval[i]))) { | ||||||
|                     v.bits().copy_to(v.nw, v.eval); |                     v.bits().copy_to(v.nw, v.eval); | ||||||
|  | @ -1717,19 +1922,83 @@ namespace bv { | ||||||
|         return *m_values[e->get_id()];  |         return *m_values[e->get_id()];  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void sls_eval::init_eval(app* t) { | ||||||
|  |         if (m.is_bool(t)) | ||||||
|  |             set(t, bval1(t)); | ||||||
|  |         else if (bv.is_bv(t)) { | ||||||
|  |             auto& v = wval(t); | ||||||
|  |             v.bits().copy_to(v.nw, v.eval); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void sls_eval::commit_eval(app* e) { | ||||||
|  |         if (m.is_bool(e)) { | ||||||
|  |             set(e, bval1(e)); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             VERIFY(wval(e).commit_eval()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void sls_eval::set_random(app* e) { | ||||||
|  |         if (bv.is_bv(e)) | ||||||
|  |             eval(e).set_random(m_rand); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool sls_eval::eval_is_correct(app* e) { | ||||||
|  |         if (!can_eval1(e)) | ||||||
|  |             return false; | ||||||
|  |         if (m.is_bool(e)) | ||||||
|  |             return bval0(e) == bval1(e); | ||||||
|  |         if (bv.is_bv(e)) { | ||||||
|  |             auto const& v = wval(e); | ||||||
|  |             return v.eval == v.bits(); | ||||||
|  |         } | ||||||
|  |         UNREACHABLE(); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool sls_eval::re_eval_is_correct(app* e) { | ||||||
|  |         if (!can_eval1(e)) | ||||||
|  |             return false; | ||||||
|  |         if (m.is_bool(e)) | ||||||
|  |             return bval0(e) ==bval1(e); | ||||||
|  |         if (bv.is_bv(e)) { | ||||||
|  |             auto const& v = eval(e); | ||||||
|  |             return v.eval == v.bits(); | ||||||
|  |         } | ||||||
|  |         UNREACHABLE(); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     expr_ref sls_eval::get_value(app* e) { | ||||||
|  |         if (m.is_bool(e)) | ||||||
|  |             return expr_ref(m.mk_bool_val(bval0(e)), m); | ||||||
|  |         else if (bv.is_bv(e)) { | ||||||
|  |             auto const& v = wval(e); | ||||||
|  |             rational n = v.get_value(); | ||||||
|  |             return expr_ref(bv.mk_numeral(n, v.bw), m); | ||||||
|  |         } | ||||||
|  |         return expr_ref(m); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     std::ostream& sls_eval::display(std::ostream& out, expr_ref_vector const& es) { |     std::ostream& sls_eval::display(std::ostream& out, expr_ref_vector const& es) { | ||||||
|         auto& terms = sort_assertions(es); |         auto& terms = sort_assertions(es); | ||||||
|         for (expr* e : terms) { |         for (expr* e : terms) { | ||||||
|             out << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " "; |             out << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " "; | ||||||
|             if (is_fixed0(e)) |             if (is_fixed0(e)) | ||||||
|                 out << "f "; |                 out << "f "; | ||||||
|             if (bv.is_bv(e)) |             display_value(out, e) << "\n"; | ||||||
|                 out << wval(e); |  | ||||||
|             else if (m.is_bool(e)) |  | ||||||
|                 out << (bval0(e) ? "T" : "F"); |  | ||||||
|             out << "\n"; |  | ||||||
|         } |         } | ||||||
|         terms.reset(); |         terms.reset(); | ||||||
|         return out; |         return out; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     std::ostream& sls_eval::display_value(std::ostream& out, expr* e) { | ||||||
|  |         if (bv.is_bv(e))  | ||||||
|  |             return out << wval(e); | ||||||
|  |         if (m.is_bool(e)) | ||||||
|  |             return out << (bval0(e)?"T":"F"); | ||||||
|  |         return out << "?"; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -25,6 +25,12 @@ namespace bv { | ||||||
| 
 | 
 | ||||||
|     class sls_fixed; |     class sls_fixed; | ||||||
| 
 | 
 | ||||||
|  |     class sls_eval_plugin { | ||||||
|  |     public: | ||||||
|  |         virtual ~sls_eval_plugin() {} | ||||||
|  |          | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     class sls_eval { |     class sls_eval { | ||||||
|         struct config { |         struct config { | ||||||
|             unsigned m_prob_randomize_extract = 50; |             unsigned m_prob_randomize_extract = 50; | ||||||
|  | @ -40,6 +46,8 @@ namespace bv { | ||||||
|         random_gen          m_rand; |         random_gen          m_rand; | ||||||
|         config              m_config; |         config              m_config; | ||||||
| 
 | 
 | ||||||
|  |         scoped_ptr_vector<sls_eval_plugin> m_plugins; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         scoped_ptr_vector<sls_valuation> m_values; // expr-id -> bv valuation
 |         scoped_ptr_vector<sls_valuation> m_values; // expr-id -> bv valuation
 | ||||||
|  | @ -93,6 +101,10 @@ namespace bv { | ||||||
|         bool try_repair_shl(bvect const& e, bvval& a, bvval& b, unsigned i); |         bool try_repair_shl(bvect const& e, bvval& a, bvval& b, unsigned i); | ||||||
|         bool try_repair_ashr(bvect const& e, bvval& a, bvval& b, unsigned i); |         bool try_repair_ashr(bvect const& e, bvval& a, bvval& b, unsigned i); | ||||||
|         bool try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i); |         bool try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i); | ||||||
|  |         bool try_repair_lshr0(bvect const& e, bvval& a, bvval const& b); | ||||||
|  |         bool try_repair_lshr1(bvect const& e, bvval const& a, bvval& b); | ||||||
|  |         bool try_repair_ashr0(bvect const& e, bvval& a, bvval const& b); | ||||||
|  |         bool try_repair_ashr1(bvect const& e, bvval const& a, bvval& b); | ||||||
|         bool try_repair_bit2bool(bvval& a, unsigned idx); |         bool try_repair_bit2bool(bvval& a, unsigned idx); | ||||||
|         bool try_repair_udiv(bvect const& e, bvval& a, bvval& b, unsigned i); |         bool try_repair_udiv(bvect const& e, bvval& a, bvval& b, unsigned i); | ||||||
|         bool try_repair_urem(bvect const& e, bvval& a, bvval& b, unsigned i); |         bool try_repair_urem(bvect const& e, bvval& a, bvval& b, unsigned i); | ||||||
|  | @ -153,6 +165,18 @@ namespace bv { | ||||||
|          |          | ||||||
|         sls_valuation& eval(app* e) const; |         sls_valuation& eval(app* e) const; | ||||||
| 
 | 
 | ||||||
|  |         void commit_eval(app* e); | ||||||
|  | 
 | ||||||
|  |         void init_eval(app* e); | ||||||
|  | 
 | ||||||
|  |         void set_random(app* e); | ||||||
|  | 
 | ||||||
|  |         bool eval_is_correct(app* e); | ||||||
|  | 
 | ||||||
|  |         bool re_eval_is_correct(app* e); | ||||||
|  | 
 | ||||||
|  |         expr_ref get_value(app* e); | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * Override evaluaton. |          * Override evaluaton. | ||||||
|          */ |          */ | ||||||
|  | @ -174,5 +198,7 @@ namespace bv { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         std::ostream& display(std::ostream& out, expr_ref_vector const& es); |         std::ostream& display(std::ostream& out, expr_ref_vector const& es); | ||||||
|  | 
 | ||||||
|  |         std::ostream& display_value(std::ostream& out, expr* e); | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -38,8 +38,8 @@ namespace bv { | ||||||
|             else |             else | ||||||
|                 ; |                 ; | ||||||
|         } |         } | ||||||
|         ev.m_todo.reset(); |  | ||||||
|         init_ranges(es); |         init_ranges(es); | ||||||
|  |         ev.m_todo.reset();         | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -49,11 +49,49 @@ namespace bv { | ||||||
|             if (is_app(e)) |             if (is_app(e)) | ||||||
|                 init_range(to_app(e), sign); |                 init_range(to_app(e), sign); | ||||||
|         } |         } | ||||||
|  |          | ||||||
|  |         for (expr* e : ev.m_todo) | ||||||
|  |             propagate_range_up(e); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void sls_fixed::propagate_range_up(expr* e) { | ||||||
|  |         expr* t, * s; | ||||||
|  |         rational v; | ||||||
|  |         if (bv.is_concat(e, t, s)) { | ||||||
|  |             auto& vals = wval(s); | ||||||
|  |             if (vals.lo() != vals.hi() && (vals.lo() < vals.hi() || vals.hi() == 0)) | ||||||
|  |                 // lo <= e
 | ||||||
|  |                 add_range(e, vals.lo(), rational::zero(), false); | ||||||
|  |             auto valt = wval(t); | ||||||
|  |             if (valt.lo() != valt.hi() && (valt.lo() < valt.hi() || valt.hi() == 0)) { | ||||||
|  |                 // (2^|s|) * lo <= e < (2^|s|) * hi
 | ||||||
|  |                 auto p = rational::power_of_two(bv.get_bv_size(s)); | ||||||
|  |                 add_range(e, valt.lo() * p, valt.hi() * p, false); | ||||||
|  |             } | ||||||
|  |         }         | ||||||
|  |         else if (bv.is_bv_add(e, s, t) && bv.is_numeral(s, v)) { | ||||||
|  |             auto& val = wval(t); | ||||||
|  |             if (val.lo() != val.hi())  | ||||||
|  |                 add_range(e, v + val.lo(), v + val.hi(), false);   | ||||||
|  |         } | ||||||
|  |         else if (bv.is_bv_add(e, t, s) && bv.is_numeral(s, v)) { | ||||||
|  |             auto& val = wval(t); | ||||||
|  |             if (val.lo() != val.hi())  | ||||||
|  |                 add_range(e, v + val.lo(), v + val.hi(), false);           | ||||||
|  |         } | ||||||
|  |         // x in [1, 4[   => -x in [-3, 0[
 | ||||||
|  |         // x in [lo, hi[ => -x in [-hi + 1, -lo + 1[
 | ||||||
|  |         else if (bv.is_bv_mul(e, s, t) && bv.is_numeral(s, v) &&  | ||||||
|  |             v + 1 == rational::power_of_two(bv.get_bv_size(e))) { | ||||||
|  |             auto& val = wval(t); | ||||||
|  |             if (val.lo() != val.hi()) | ||||||
|  |                 add_range(e, -val.hi() + 1, - val.lo() + 1, false); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // s <=s t           <=> s + K <= t + K,   K = 2^{bw-1}
 |     // s <=s t           <=> s + K <= t + K,   K = 2^{bw-1}
 | ||||||
| 
 | 
 | ||||||
|     void sls_fixed::init_range(app* e, bool sign) { |     bool sls_fixed::init_range(app* e, bool sign) { | ||||||
|         expr* s, * t, * x, * y; |         expr* s, * t, * x, * y; | ||||||
|         rational a, b; |         rational a, b; | ||||||
|         unsigned idx; |         unsigned idx; | ||||||
|  | @ -64,56 +102,116 @@ namespace bv { | ||||||
|         if (bv.is_ule(e, s, t)) { |         if (bv.is_ule(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(x, a, y, b, sign); |             return init_range(x, a, y, b, sign); | ||||||
|         } |         } | ||||||
|         else if (bv.is_ult(e, s, t)) { |         else if (bv.is_ult(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(y, b, x, a, !sign); |             return init_range(y, b, x, a, !sign); | ||||||
|         }             |         }             | ||||||
|         else if (bv.is_uge(e, s, t)) { |         else if (bv.is_uge(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(y, b, x, a, sign); |             return init_range(y, b, x, a, sign); | ||||||
|         }             |         }             | ||||||
|         else if (bv.is_ugt(e, s, t)) { |         else if (bv.is_ugt(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(x, a, y, b, !sign); |             return init_range(x, a, y, b, !sign); | ||||||
|         }             |         }             | ||||||
|         else if (bv.is_sle(e, s, t)) { |         else if (bv.is_sle(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(x, a + N(s), y, b + N(s), sign); |             return init_range(x, a + N(s), y, b + N(s), sign); | ||||||
|         }             |         }             | ||||||
|         else if (bv.is_slt(e, s, t)) { |         else if (bv.is_slt(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(y, b + N(s), x, a + N(s), !sign); |             return init_range(y, b + N(s), x, a + N(s), !sign); | ||||||
|         } |         } | ||||||
|         else if (bv.is_sge(e, s, t)) { |         else if (bv.is_sge(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(y, b + N(s), x, a + N(s), sign); |             return init_range(y, b + N(s), x, a + N(s), sign); | ||||||
|         } |         } | ||||||
|         else if (bv.is_sgt(e, s, t)) { |         else if (bv.is_sgt(e, s, t)) { | ||||||
|             get_offset(s, x, a); |             get_offset(s, x, a); | ||||||
|             get_offset(t, y, b); |             get_offset(t, y, b); | ||||||
|             init_range(x, a + N(s), y, b + N(s), !sign); |             return init_range(x, a + N(s), y, b + N(s), !sign); | ||||||
|         } |         } | ||||||
|         else if (!sign && m.is_eq(e, s, t)) { |         else if (m.is_eq(e, s, t)) { | ||||||
|             if (bv.is_numeral(s, a)) |             if (bv.is_numeral(s, a)) | ||||||
|                 // t - a <= 0
 |                 init_eq(t, a, sign); | ||||||
|                 init_range(t, -a, nullptr, rational(0), false); |  | ||||||
|             else if (bv.is_numeral(t, a)) |             else if (bv.is_numeral(t, a)) | ||||||
|                 init_range(s, -a, nullptr, rational(0), false); |                 init_eq(s, a, sign); | ||||||
|  |             else | ||||||
|  |                 return false; | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|         else if (bv.is_bit2bool(e, s, idx)) { |         else if (bv.is_bit2bool(e, s, idx)) { | ||||||
|             auto& val = wval(s); |             auto& val = wval(s); | ||||||
|             val.try_set_bit(idx, !sign); |             val.try_set_bit(idx, !sign); | ||||||
|             val.fixed.set(idx, true); |             val.fixed.set(idx, true); | ||||||
|             val.tighten_range(); |             val.tighten_range(); | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool sls_fixed::init_eq(expr* t, rational const& a, bool sign) {         | ||||||
|  |         unsigned lo, hi; | ||||||
|  |         rational b(0); | ||||||
|  |         // verbose_stream() << mk_bounded_pp(t, m) << " == " << a << "\n";
 | ||||||
|  |         expr* s = nullptr;         | ||||||
|  |         if (sign) | ||||||
|  |             // 1 <= t - a
 | ||||||
|  |             init_range(nullptr, rational(1), t, -a, false); | ||||||
|  |         else | ||||||
|  |             // t - a <= 0
 | ||||||
|  |             init_range(t, -a, nullptr, rational::zero(), false); | ||||||
|  |         if (!sign && bv.is_bv_not(t, s)) { | ||||||
|  |             for (unsigned i = 0; i < bv.get_bv_size(s); ++i) | ||||||
|  |                 if (!a.get_bit(i)) | ||||||
|  |                     b += rational::power_of_two(i); | ||||||
|  |             init_eq(s, b, false); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         expr* x, * y; | ||||||
|  |         if (!sign && bv.is_concat(t, x, y)) { | ||||||
|  |             auto sz = bv.get_bv_size(y); | ||||||
|  |             auto k = rational::power_of_two(sz); | ||||||
|  |             init_eq(y, mod(a, k), false); | ||||||
|  |             init_eq(x, div(a + k - 1, k), false); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (bv.is_extract(t, lo, hi, s)) { | ||||||
|  |             if (hi == lo) { | ||||||
|  |                 sign = sign ? a == 1 : a == 0; | ||||||
|  |                 auto& val = wval(s); | ||||||
|  |                 if (val.try_set_bit(lo, !sign))  | ||||||
|  |                     val.fixed.set(lo, true);                                     | ||||||
|  |                 val.tighten_range(); | ||||||
|  |             } | ||||||
|  |             else if (!sign) { | ||||||
|  |                 auto& val = wval(s); | ||||||
|  |                 for (unsigned i = lo; i <= hi; ++i)  | ||||||
|  |                     if (val.try_set_bit(i, a.get_bit(i - lo))) | ||||||
|  |                         val.fixed.set(i, true);                 | ||||||
|  |                 val.tighten_range(); | ||||||
|  |                 // verbose_stream() << lo << " " << hi << " " << val << " := " << a << "\n";
 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!sign && hi + 1 == bv.get_bv_size(s)) { | ||||||
|  |                 // s < 2^lo * (a + 1) 
 | ||||||
|  |                 rational b = rational::power_of_two(lo) * (a + 1) - 1; | ||||||
|  |                 rational offset; | ||||||
|  |                 get_offset(s, t, offset); | ||||||
|  |                 // t + offset <= b
 | ||||||
|  |                 init_range(t, offset, nullptr, b, false); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // 
 |     // 
 | ||||||
|  | @ -125,52 +223,65 @@ namespace bv { | ||||||
|     // a < x + b         <=> ! (x + b <= a) <=> x not in [-a, b - a [ <=> x in [b - a, -a [         a != -1
 |     // a < x + b         <=> ! (x + b <= a) <=> x not in [-a, b - a [ <=> x in [b - a, -a [         a != -1
 | ||||||
|     // x + a < x + b     <=> ! (x + b <= x + a) <=> x in [-a, -b [                                  a != b
 |     // x + a < x + b     <=> ! (x + b <= x + a) <=> x in [-a, -b [                                  a != b
 | ||||||
|     // 
 |     // 
 | ||||||
|     void sls_fixed::init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign) { |     bool sls_fixed::init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign) { | ||||||
|         if (!x && !y) |         if (!x && !y) | ||||||
|             return; |             return false; | ||||||
|         if (!x) { |         if (!x)  | ||||||
|             // a <= y + b
 |             return add_range(y, a - b, -b, sign); | ||||||
|             if (a == 0) |         else if (!y)  | ||||||
|                 return; |             return add_range(x, -a, b - a + 1, sign);         | ||||||
|             auto& v = wval(y); |         else if (x == y)  | ||||||
|             if (!sign) |             return add_range(x, -a, -b, sign); | ||||||
|                 v.add_range(a - b, -b); |         return false; | ||||||
|             else |     } | ||||||
|                 v.add_range(-b, a - b); |  | ||||||
|         } |  | ||||||
|         else if (!y) { |  | ||||||
| 
 | 
 | ||||||
|             if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 0) |     bool sls_fixed::add_range(expr* e, rational lo, rational hi, bool sign) { | ||||||
|                 return; |         auto& v = wval(e); | ||||||
|             auto& v = wval(x); |         lo = mod(lo, rational::power_of_two(bv.get_bv_size(e))); | ||||||
|             if (!sign) |         hi = mod(hi, rational::power_of_two(bv.get_bv_size(e))); | ||||||
|                 v.add_range(-a, b - a + 1); |         if (lo == hi) | ||||||
|             else  |             return false; | ||||||
|                 v.add_range(b - a + 1, -a); |         if (sign) | ||||||
|  |             std::swap(lo, hi); | ||||||
|  |         v.add_range(lo, hi); | ||||||
|  |         expr* x, * y; | ||||||
|  |         if (v.lo() == 0 && bv.is_concat(e, x, y)) { | ||||||
|  |             auto sz = bv.get_bv_size(y); | ||||||
|  |             auto k = rational::power_of_two(sz); | ||||||
|  |             lo = v.lo(); | ||||||
|  |             hi = v.hi(); | ||||||
|  |             if (hi <= k) { | ||||||
|  |                 add_range(y, lo, hi, false); | ||||||
|  |                 init_eq(x, lo, false); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 hi = div(hi + k - 1, k); | ||||||
|  |                 add_range(x, lo, hi, false); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         else if (x == y) { |         return true; | ||||||
|             if (a == b) |  | ||||||
|                 return; |  | ||||||
|             auto& v = wval(x); |  | ||||||
|             if (!sign) |  | ||||||
|                 v.add_range(-a, -b); |  | ||||||
|             else |  | ||||||
|                 v.add_range(-b, -a); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls_fixed::get_offset(expr* e, expr*& x, rational& offset) { |     void sls_fixed::get_offset(expr* e, expr*& x, rational& offset) { | ||||||
|         expr* s, * t; |         expr* s, * t; | ||||||
|         x = e; |         x = e; | ||||||
|         offset = 0; |         offset = 0; | ||||||
|         if (bv.is_bv_add(e, s, t)) { |         rational n; | ||||||
|             if (bv.is_numeral(s, offset)) |         while (true) { | ||||||
|  |             if (bv.is_bv_add(x, s, t) && bv.is_numeral(s, n)) { | ||||||
|                 x = t; |                 x = t; | ||||||
|             else if (bv.is_numeral(t, offset)) |                 offset += n; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             if (bv.is_bv_add(x, s, t) && bv.is_numeral(t, n)) { | ||||||
|                 x = s; |                 x = s; | ||||||
|  |                 offset += n; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|         else if (bv.is_numeral(e, offset)) |         if (bv.is_numeral(e, n)) | ||||||
|  |             offset += n, | ||||||
|             x = nullptr; |             x = nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -258,11 +369,6 @@ namespace bv { | ||||||
|         case OP_BADD: { |         case OP_BADD: { | ||||||
|             auto& a = wval(e->get_arg(0)); |             auto& a = wval(e->get_arg(0)); | ||||||
|             auto& b = wval(e->get_arg(1)); |             auto& b = wval(e->get_arg(1)); | ||||||
|             rational r; |  | ||||||
|             if (bv.is_numeral(e->get_arg(0), r) && b.has_range())  |  | ||||||
|                 v.add_range(r + b.lo(), r + b.hi());             |  | ||||||
|             else if (bv.is_numeral(e->get_arg(1), r) && a.has_range())  |  | ||||||
|                 v.add_range(r + a.lo(), r + a.hi());             |  | ||||||
|             bool pfixed = true; |             bool pfixed = true; | ||||||
|             for (unsigned i = 0; i < v.bw; ++i) { |             for (unsigned i = 0; i < v.bw; ++i) { | ||||||
|                 if (pfixed && a.fixed.get(i) && b.fixed.get(i))  |                 if (pfixed && a.fixed.get(i) && b.fixed.get(i))  | ||||||
|  | @ -277,7 +383,6 @@ namespace bv { | ||||||
|                     v.fixed.set(i, false); |                     v.fixed.set(i, false); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case OP_BMUL: { |         case OP_BMUL: { | ||||||
|  |  | ||||||
|  | @ -30,9 +30,12 @@ namespace bv { | ||||||
|         bv_util&            bv; |         bv_util&            bv; | ||||||
| 
 | 
 | ||||||
|         void init_ranges(expr_ref_vector const& es); |         void init_ranges(expr_ref_vector const& es); | ||||||
|         void init_range(app* e, bool sign); |         bool init_range(app* e, bool sign); | ||||||
|         void init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign); |         void propagate_range_up(expr* e); | ||||||
|  |         bool init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign); | ||||||
|         void get_offset(expr* e, expr*& x, rational& offset); |         void get_offset(expr* e, expr*& x, rational& offset); | ||||||
|  |         bool init_eq(expr* e, rational const& v, bool sign); | ||||||
|  |         bool add_range(expr* e, rational lo, rational hi, bool sign); | ||||||
| 
 | 
 | ||||||
|         void init_fixed_basic(app* e); |         void init_fixed_basic(app* e); | ||||||
|         void init_fixed_bv(app* e); |         void init_fixed_bv(app* e); | ||||||
|  |  | ||||||
|  | @ -20,12 +20,14 @@ Author: | ||||||
| 
 | 
 | ||||||
| #include "ast/ast_ll_pp.h" | #include "ast/ast_ll_pp.h" | ||||||
| #include "ast/sls/bv_sls.h" | #include "ast/sls/bv_sls.h" | ||||||
|  | #include "ast/rewriter/th_rewriter.h" | ||||||
| 
 | 
 | ||||||
| namespace bv { | namespace bv { | ||||||
| 
 | 
 | ||||||
|     sls_terms::sls_terms(ast_manager& m):  |     sls_terms::sls_terms(ast_manager& m):  | ||||||
|         m(m),  |         m(m),  | ||||||
|         bv(m), |         bv(m), | ||||||
|  |         m_rewriter(m), | ||||||
|         m_assertions(m), |         m_assertions(m), | ||||||
|         m_pinned(m), |         m_pinned(m), | ||||||
|         m_translated(m),  |         m_translated(m),  | ||||||
|  | @ -40,18 +42,20 @@ namespace bv { | ||||||
|         expr* top = e; |         expr* top = e; | ||||||
|         m_pinned.push_back(e); |         m_pinned.push_back(e); | ||||||
|         m_todo.push_back(e); |         m_todo.push_back(e); | ||||||
|         expr_fast_mark1 mark; |         { | ||||||
|         for (unsigned i = 0; i < m_todo.size(); ++i) { |             expr_fast_mark1 mark; | ||||||
|             expr* e = m_todo[i]; |             for (unsigned i = 0; i < m_todo.size(); ++i) { | ||||||
|             if (!is_app(e)) |                 expr* e = m_todo[i]; | ||||||
|                 continue; |                 if (!is_app(e)) | ||||||
|             if (m_translated.get(e->get_id(), nullptr)) |                     continue; | ||||||
|                 continue; |                 if (m_translated.get(e->get_id(), nullptr)) | ||||||
|             if (mark.is_marked(e)) |                     continue; | ||||||
|                 continue; |                 if (mark.is_marked(e)) | ||||||
|             mark.mark(e); |                     continue; | ||||||
|             for (auto arg : *to_app(e)) |                 mark.mark(e); | ||||||
|                 m_todo.push_back(arg); |                 for (auto arg : *to_app(e)) | ||||||
|  |                     m_todo.push_back(arg); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         std::stable_sort(m_todo.begin(), m_todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); }); |         std::stable_sort(m_todo.begin(), m_todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); }); | ||||||
|         for (expr* e : m_todo) |         for (expr* e : m_todo) | ||||||
|  | @ -127,7 +131,7 @@ namespace bv { | ||||||
|         m_translated.setx(e->get_id(), r); |         m_translated.setx(e->get_id(), r); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     expr* sls_terms::mk_sdiv(expr* x, expr* y) { |     expr_ref sls_terms::mk_sdiv(expr* x, expr* y) { | ||||||
|         // d = udiv(abs(x), abs(y))
 |         // d = udiv(abs(x), abs(y))
 | ||||||
|         // y = 0, x >= 0 -> -1
 |         // y = 0, x >= 0 -> -1
 | ||||||
|         // y = 0, x < 0 -> 1
 |         // y = 0, x < 0 -> 1
 | ||||||
|  | @ -141,17 +145,18 @@ namespace bv { | ||||||
|         expr_ref z(bv.mk_zero(sz), m); |         expr_ref z(bv.mk_zero(sz), m); | ||||||
|         expr* signx = bv.mk_ule(bv.mk_numeral(N / 2, sz), x); |         expr* signx = bv.mk_ule(bv.mk_numeral(N / 2, sz), x); | ||||||
|         expr* signy = bv.mk_ule(bv.mk_numeral(N / 2, sz), y); |         expr* signy = bv.mk_ule(bv.mk_numeral(N / 2, sz), y); | ||||||
|         expr* absx = m.mk_ite(signx, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), x), x); |         expr* absx = m.mk_ite(signx, bv.mk_bv_neg(x), x); | ||||||
|         expr* absy = m.mk_ite(signy, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), y), y); |         expr* absy = m.mk_ite(signy, bv.mk_bv_neg(y), y); | ||||||
|         expr* d = bv.mk_bv_udiv(absx, absy); |         expr* d = bv.mk_bv_udiv(absx, absy); | ||||||
|         expr* r = m.mk_ite(m.mk_eq(signx, signy), d, bv.mk_bv_neg(d)); |         expr_ref r(m.mk_ite(m.mk_eq(signx, signy), d, bv.mk_bv_neg(d)), m); | ||||||
|         r = m.mk_ite(m.mk_eq(z, y), |         r = m.mk_ite(m.mk_eq(z, y), | ||||||
|                 m.mk_ite(signx, bv.mk_one(sz), bv.mk_numeral(N - 1, sz)), |                      m.mk_ite(signx, bv.mk_one(sz), bv.mk_numeral(N - 1, sz)), | ||||||
|                 m.mk_ite(m.mk_eq(x, z), z, r)); |                      m.mk_ite(m.mk_eq(x, z), z, r)); | ||||||
|  |         m_rewriter(r); | ||||||
|         return r; |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     expr* sls_terms::mk_smod(expr* x, expr* y) { |     expr_ref sls_terms::mk_smod(expr* x, expr* y) { | ||||||
|         // u := umod(abs(x), abs(y))
 |         // u := umod(abs(x), abs(y))
 | ||||||
|         // u = 0 ->  0
 |         // u = 0 ->  0
 | ||||||
|         // y = 0 ->  x
 |         // y = 0 ->  x
 | ||||||
|  | @ -164,21 +169,24 @@ namespace bv { | ||||||
|         expr_ref abs_x(m.mk_ite(bv.mk_sle(z, x), x, bv.mk_bv_neg(x)), m); |         expr_ref abs_x(m.mk_ite(bv.mk_sle(z, x), x, bv.mk_bv_neg(x)), m); | ||||||
|         expr_ref abs_y(m.mk_ite(bv.mk_sle(z, y), y, bv.mk_bv_neg(y)), m); |         expr_ref abs_y(m.mk_ite(bv.mk_sle(z, y), y, bv.mk_bv_neg(y)), m); | ||||||
|         expr_ref u(bv.mk_bv_urem(abs_x, abs_y), m); |         expr_ref u(bv.mk_bv_urem(abs_x, abs_y), m); | ||||||
|         return |         expr_ref r(m); | ||||||
|             m.mk_ite(m.mk_eq(u, z), z, |         r = m.mk_ite(m.mk_eq(u, z), z, | ||||||
|                 m.mk_ite(m.mk_eq(y, z), x, |                 m.mk_ite(m.mk_eq(y, z), x, | ||||||
|                     m.mk_ite(m.mk_and(bv.mk_sle(z, x), bv.mk_sle(z, x)), u, |                     m.mk_ite(m.mk_and(bv.mk_sle(z, x), bv.mk_sle(z, x)), u, | ||||||
|                         m.mk_ite(bv.mk_sle(z, x), bv.mk_bv_add(y, u), |                         m.mk_ite(bv.mk_sle(z, x), bv.mk_bv_add(y, u), | ||||||
|                             m.mk_ite(bv.mk_sle(z, y), bv.mk_bv_sub(y, u), bv.mk_bv_neg(u)))))); |                             m.mk_ite(bv.mk_sle(z, y), bv.mk_bv_sub(y, u), bv.mk_bv_neg(u)))))); | ||||||
|                        |         m_rewriter(r); | ||||||
|  |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     expr* sls_terms::mk_srem(expr* x, expr* y) { |     expr_ref sls_terms::mk_srem(expr* x, expr* y) { | ||||||
|         // y = 0 -> x
 |         // y = 0 -> x
 | ||||||
|         // else x - sdiv(x, y) * y
 |         // else x - sdiv(x, y) * y
 | ||||||
|         return  |         expr_ref r(m); | ||||||
|             m.mk_ite(m.mk_eq(y, bv.mk_zero(bv.get_bv_size(x))), |         r = m.mk_ite(m.mk_eq(y, bv.mk_zero(bv.get_bv_size(x))), | ||||||
|                      x, bv.mk_bv_sub(x, bv.mk_bv_mul(y, mk_sdiv(x, y)))); |                      x, bv.mk_bv_sub(x, bv.mk_bv_mul(y, mk_sdiv(x, y)))); | ||||||
|  |         m_rewriter(r); | ||||||
|  |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -198,6 +206,7 @@ namespace bv { | ||||||
|                 m_todo.push_back(arg); |                 m_todo.push_back(arg); | ||||||
|         }        |         }        | ||||||
|         // populate parents
 |         // populate parents
 | ||||||
|  |         m_parents.reset(); | ||||||
|         m_parents.reserve(m_terms.size()); |         m_parents.reserve(m_terms.size()); | ||||||
|         for (expr* e : m_terms) { |         for (expr* e : m_terms) { | ||||||
|             if (!e || !is_app(e)) |             if (!e || !is_app(e)) | ||||||
|  | @ -205,8 +214,16 @@ namespace bv { | ||||||
|             for (expr* arg : *to_app(e)) |             for (expr* arg : *to_app(e)) | ||||||
|                 m_parents[arg->get_id()].push_back(e);                 |                 m_parents[arg->get_id()].push_back(e);                 | ||||||
|         } |         } | ||||||
|  |         m_assertion_set.reset(); | ||||||
|         for (auto a : m_assertions) |         for (auto a : m_assertions) | ||||||
|             m_assertion_set.insert(a->get_id()); |             m_assertion_set.insert(a->get_id()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void sls_terms::updt_params(params_ref const& p) { | ||||||
|  |         params_ref q = p; | ||||||
|  |         q.set_bool("flat", false); | ||||||
|  |         m_rewriter.updt_params(q); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ Author: | ||||||
| #include "util/scoped_ptr_vector.h" | #include "util/scoped_ptr_vector.h" | ||||||
| #include "util/uint_set.h" | #include "util/uint_set.h" | ||||||
| #include "ast/ast.h" | #include "ast/ast.h" | ||||||
|  | #include "ast/rewriter/th_rewriter.h" | ||||||
| #include "ast/sls/sls_stats.h" | #include "ast/sls/sls_stats.h" | ||||||
| #include "ast/sls/sls_powers.h" | #include "ast/sls/sls_powers.h" | ||||||
| #include "ast/sls/sls_valuation.h" | #include "ast/sls/sls_valuation.h" | ||||||
|  | @ -31,6 +32,7 @@ namespace bv { | ||||||
|     class sls_terms { |     class sls_terms { | ||||||
|         ast_manager&        m; |         ast_manager&        m; | ||||||
|         bv_util             bv; |         bv_util             bv; | ||||||
|  |         th_rewriter         m_rewriter; | ||||||
|         ptr_vector<expr>    m_todo, m_args; |         ptr_vector<expr>    m_todo, m_args; | ||||||
|         expr_ref_vector     m_assertions, m_pinned, m_translated; |         expr_ref_vector     m_assertions, m_pinned, m_translated; | ||||||
|         app_ref_vector      m_terms; |         app_ref_vector      m_terms; | ||||||
|  | @ -40,13 +42,15 @@ namespace bv { | ||||||
|         expr* ensure_binary(expr* e); |         expr* ensure_binary(expr* e); | ||||||
|         void ensure_binary_core(expr* e); |         void ensure_binary_core(expr* e); | ||||||
| 
 | 
 | ||||||
|         expr* mk_sdiv(expr* x, expr* y); |         expr_ref mk_sdiv(expr* x, expr* y); | ||||||
|         expr* mk_smod(expr* x, expr* y); |         expr_ref mk_smod(expr* x, expr* y); | ||||||
|         expr* mk_srem(expr* x, expr* y); |         expr_ref mk_srem(expr* x, expr* y); | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
|         sls_terms(ast_manager& m); |         sls_terms(ast_manager& m); | ||||||
| 
 | 
 | ||||||
|  |         void updt_params(params_ref const& p); | ||||||
|  |          | ||||||
|         /**
 |         /**
 | ||||||
|         * Add constraints |         * Add constraints | ||||||
|         */ |         */ | ||||||
|  |  | ||||||
|  | @ -421,6 +421,7 @@ lbool sls_engine::search() { | ||||||
| 
 | 
 | ||||||
|         // get candidate variables
 |         // get candidate variables
 | ||||||
|         ptr_vector<func_decl> & to_evaluate = m_tracker.get_unsat_constants(m_assertions); |         ptr_vector<func_decl> & to_evaluate = m_tracker.get_unsat_constants(m_assertions); | ||||||
|  |          | ||||||
|         if (to_evaluate.empty()) |         if (to_evaluate.empty()) | ||||||
|         { |         { | ||||||
|             res = l_true; |             res = l_true; | ||||||
|  | @ -514,6 +515,12 @@ lbool sls_engine::operator()() { | ||||||
|     if (m_restart_init) |     if (m_restart_init) | ||||||
|         m_tracker.randomize(m_assertions); |         m_tracker.randomize(m_assertions); | ||||||
| 
 | 
 | ||||||
|  |     return search_loop(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | lbool sls_engine::search_loop() { | ||||||
|  | 
 | ||||||
|     lbool res = l_undef; |     lbool res = l_undef; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|  | @ -533,7 +540,6 @@ lbool sls_engine::operator()() { | ||||||
|     } while (res != l_true && m_stats.m_restarts++ < m_max_restarts); |     } while (res != l_true && m_stats.m_restarts++ < m_max_restarts); | ||||||
| 
 | 
 | ||||||
|     verbose_stream() << "(restarts: " << m_stats.m_restarts << " flips: " << m_stats.m_moves << " fps: " << (m_stats.m_moves / m_stats.m_stopwatch.get_current_seconds()) << ")" << std::endl; |     verbose_stream() << "(restarts: " << m_stats.m_restarts << " flips: " << m_stats.m_moves << " fps: " << (m_stats.m_moves / m_stats.m_stopwatch.get_current_seconds()) << ")" << std::endl; | ||||||
|      |  | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -79,8 +79,12 @@ public: | ||||||
|     void mk_inv(unsigned bv_sz, const mpz & old_value, mpz & inverted); |     void mk_inv(unsigned bv_sz, const mpz & old_value, mpz & inverted); | ||||||
|     void mk_flip(sort * s, const mpz & old_value, unsigned bit, mpz & flipped);             |     void mk_flip(sort * s, const mpz & old_value, unsigned bit, mpz & flipped);             | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     lbool search();   |     lbool search();   | ||||||
| 
 | 
 | ||||||
|  |     lbool search_loop(); | ||||||
|  | 
 | ||||||
|     lbool operator()(); |     lbool operator()(); | ||||||
| 
 | 
 | ||||||
|     mpz & get_value(expr * n) { return m_tracker.get_value(n); } |     mpz & get_value(expr * n) { return m_tracker.get_value(n); } | ||||||
|  |  | ||||||
|  | @ -56,6 +56,20 @@ namespace bv { | ||||||
|         return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) >= 0; |         return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) >= 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool operator<=(digit_t a, bvect const& b) { | ||||||
|  |         for (unsigned i = 1; i < b.nw; ++i) | ||||||
|  |             if (0 != b[i]) | ||||||
|  |                 return true; | ||||||
|  |         return mpn_manager().compare(&a, 1, b.data(), 1) <= 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool operator<=(bvect const& a, digit_t b) { | ||||||
|  |         for (unsigned i = 1; i < a.nw; ++i) | ||||||
|  |             if (0 != a[i]) | ||||||
|  |                 return false; | ||||||
|  |         return mpn_manager().compare(a.data(), 1, &b, 1) <= 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     std::ostream& operator<<(std::ostream& out, bvect const& v) { |     std::ostream& operator<<(std::ostream& out, bvect const& v) { | ||||||
|         out << std::hex; |         out << std::hex; | ||||||
|         bool nz = false; |         bool nz = false; | ||||||
|  | @ -83,11 +97,63 @@ namespace bv { | ||||||
|         return r; |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     unsigned bvect::to_nat(unsigned max_n) const { | ||||||
|  |         SASSERT(max_n < UINT_MAX / 2); | ||||||
|  |         unsigned p = 1; | ||||||
|  |         unsigned value = 0; | ||||||
|  |         for (unsigned i = 0; i < bw; ++i) { | ||||||
|  |             if (p >= max_n) { | ||||||
|  |                 for (unsigned j = i; j < bw; ++j) | ||||||
|  |                     if (get(j)) | ||||||
|  |                         return max_n; | ||||||
|  |                 return value; | ||||||
|  |             } | ||||||
|  |             if (get(i)) | ||||||
|  |                 value += p; | ||||||
|  |             p <<= 1; | ||||||
|  |         } | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bvect& bvect::set_shift_right(bvect const& a, bvect const& b) { | ||||||
|  |         SASSERT(a.bw == b.bw); | ||||||
|  |         unsigned shift = b.to_nat(b.bw); | ||||||
|  |         return set_shift_right(a, shift); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bvect& bvect::set_shift_right(bvect const& a, unsigned shift) { | ||||||
|  |         set_bw(a.bw); | ||||||
|  |         if (shift == 0) | ||||||
|  |             a.copy_to(a.nw, *this); | ||||||
|  |         else if (shift >= a.bw) | ||||||
|  |             set_zero(); | ||||||
|  |         else | ||||||
|  |             for (unsigned i = 0; i < bw; ++i) | ||||||
|  |                 set(i, i + shift < bw ? a.get(i + shift) : false); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bvect& bvect::set_shift_left(bvect const& a, bvect const& b) { | ||||||
|  |         set_bw(a.bw); | ||||||
|  |         SASSERT(a.bw == b.bw); | ||||||
|  |         unsigned shift = b.to_nat(b.bw); | ||||||
|  |         if (shift == 0) | ||||||
|  |             a.copy_to(a.nw, *this); | ||||||
|  |         else if (shift >= a.bw) | ||||||
|  |             set_zero(); | ||||||
|  |         else | ||||||
|  |             for (unsigned i = bw; i-- > 0; ) | ||||||
|  |                 set(i, i >= shift ? a.get(i - shift) : false); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     sls_valuation::sls_valuation(unsigned bw) { |     sls_valuation::sls_valuation(unsigned bw) { | ||||||
|         set_bw(bw); |         set_bw(bw); | ||||||
|         m_lo.set_bw(bw); |         m_lo.set_bw(bw); | ||||||
|         m_hi.set_bw(bw); |         m_hi.set_bw(bw); | ||||||
|         m_bits.set_bw(bw); |         m_bits.set_bw(bw); | ||||||
|  |         m_tmp.set_bw(bw); | ||||||
|         fixed.set_bw(bw); |         fixed.set_bw(bw); | ||||||
|         eval.set_bw(bw); |         eval.set_bw(bw); | ||||||
|         // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated        
 |         // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated        
 | ||||||
|  | @ -108,8 +174,10 @@ namespace bv { | ||||||
|         for (unsigned i = 0; i < nw; ++i) |         for (unsigned i = 0; i < nw; ++i) | ||||||
|             if (0 != (fixed[i] & (m_bits[i] ^ eval[i])))                  |             if (0 != (fixed[i] & (m_bits[i] ^ eval[i])))                  | ||||||
|                 return false; |                 return false; | ||||||
|  |              | ||||||
|         if (!in_range(eval))  |         if (!in_range(eval))  | ||||||
|             return false; |             return false; | ||||||
|  |          | ||||||
|         for (unsigned i = 0; i < nw; ++i)  |         for (unsigned i = 0; i < nw; ++i)  | ||||||
|             m_bits[i] = eval[i];  |             m_bits[i] = eval[i];  | ||||||
|         SASSERT(well_formed());  |         SASSERT(well_formed());  | ||||||
|  | @ -137,143 +205,75 @@ namespace bv { | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|     // largest dst <= src and dst is feasible
 |     // largest dst <= src and dst is feasible
 | ||||||
|     // set dst := src & (~fixed | bits)
 |  | ||||||
|     // 
 |  | ||||||
|     // increment dst if dst < src by setting bits below msb(src & ~dst) to 1
 |  | ||||||
|     // 
 |  | ||||||
|     // if dst < lo < hi:
 |  | ||||||
|     //    return false
 |  | ||||||
|     // if lo < hi <= dst:
 |  | ||||||
|     //    set dst := hi - 1
 |  | ||||||
|     // if hi <= dst < lo
 |  | ||||||
|     //    set dst := hi - 1
 |  | ||||||
|     //
 |     //
 | ||||||
| 
 | 
 | ||||||
|     bool sls_valuation::get_at_most(bvect const& src, bvect& dst) const { |     bool sls_valuation::get_at_most(bvect const& src, bvect& dst) const { | ||||||
|         SASSERT(!has_overflow(src)); |         SASSERT(!has_overflow(src)); | ||||||
|         for (unsigned i = 0; i < nw; ++i) |         src.copy_to(nw, dst); | ||||||
|             dst[i] = src[i] & (~fixed[i] | m_bits[i]); |         sup_feasible(dst); | ||||||
| 
 |         if (in_range(dst)) { | ||||||
|         //
 |             SASSERT(can_set(dst)); | ||||||
|         // If dst < src, then find the most significant 
 |             return true; | ||||||
|         // bit where src[idx] = 1, dst[idx] = 0
 |  | ||||||
|         // set dst[j] = bits_j | ~fixed_j for j < idx
 |  | ||||||
|         //
 |  | ||||||
|         for (unsigned i = nw; i-- > 0; ) { |  | ||||||
|             if (0 != (~dst[i] & src[i])) { |  | ||||||
|                 auto idx = log2(~dst[i] & src[i]); |  | ||||||
|                 auto mask = (1 << idx) - 1; |  | ||||||
|                 dst[i] = (~fixed[i] & mask) | dst[i]; |  | ||||||
|                 for (unsigned j = i; j-- > 0; ) |  | ||||||
|                     dst[j] = (~fixed[j] | m_bits[j]); |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         }         |         }         | ||||||
|         SASSERT(!has_overflow(dst)); |         if (dst < m_lo && m_lo < m_hi) // dst < lo < hi 
 | ||||||
|         return round_down(dst); |             return false; | ||||||
|  |         if (is_zero(m_hi)) | ||||||
|  |             return false; | ||||||
|  |         m_hi.copy_to(nw, dst); // hi <= dst < lo or lo < hi <= dst
 | ||||||
|  |         sub1(dst);        | ||||||
|  |         SASSERT(can_set(dst)); | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|     // smallest dst >= src and dst is feasible with respect to this.
 |     // smallest dst >= src and dst is feasible with respect to this.
 | ||||||
|     // set dst := (src & ~fixed) | (fixed & bits)
 |  | ||||||
|     // 
 |  | ||||||
|     // decrement dst if dst > src by setting bits below msb to 0 unless fixed
 |  | ||||||
|     // 
 |  | ||||||
|     // if lo < hi <= dst
 |  | ||||||
|     //    return false
 |  | ||||||
|     // if dst < lo < hi:
 |  | ||||||
|     //    set dst := lo
 |  | ||||||
|     // if hi <= dst < lo
 |  | ||||||
|     //    set dst := lo
 |  | ||||||
|     // 
 |  | ||||||
|     bool sls_valuation::get_at_least(bvect const& src, bvect& dst) const { |     bool sls_valuation::get_at_least(bvect const& src, bvect& dst) const { | ||||||
|         SASSERT(!has_overflow(src)); |         SASSERT(!has_overflow(src)); | ||||||
|         for (unsigned i = 0; i < nw; ++i) |         src.copy_to(nw, dst); | ||||||
|             dst[i] = (~fixed[i] & src[i]) | (fixed[i] & m_bits[i]); |         dst.set_bw(bw); | ||||||
| 
 |         inf_feasible(dst); | ||||||
|         //
 |         if (in_range(dst)) { | ||||||
|         // If dst > src, then find the most significant 
 |             SASSERT(can_set(dst)); | ||||||
|         // bit where src[idx] = 0, dst[idx] = 1
 |             return true; | ||||||
|         // set dst[j] = dst[j] & fixed_j for j < idx
 |  | ||||||
|         //
 |  | ||||||
|         for (unsigned i = nw; i-- > 0; ) { |  | ||||||
|             if (0 != (dst[i] & ~src[i])) { |  | ||||||
|                 auto idx = log2(dst[i] & ~src[i]); |  | ||||||
|                 auto mask = (1 << idx); |  | ||||||
|                 dst[i] = dst[i] & (fixed[i] | mask); |  | ||||||
|                 for (unsigned j = i; j-- > 0; ) |  | ||||||
|                     dst[j] = dst[j] & fixed[j]; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         SASSERT(!has_overflow(dst)); |  | ||||||
|         return round_up(dst); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     bool sls_valuation::round_up(bvect& dst) const { |         if (dst > m_lo) | ||||||
|         if (m_lo < m_hi) { |  | ||||||
|             if (m_hi <= dst) |  | ||||||
|                 return false; |  | ||||||
|             if (m_lo > dst) |  | ||||||
|                 set(dst, m_lo); |  | ||||||
|         } |  | ||||||
|         else if (m_hi <= dst && m_lo > dst) |  | ||||||
|             set(dst, m_lo); |  | ||||||
|         SASSERT(!has_overflow(dst)); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool sls_valuation::round_down(bvect& dst) const { |  | ||||||
|         if (m_lo < m_hi) { |  | ||||||
|             if (m_lo > dst) |  | ||||||
|                 return false; |  | ||||||
|             if (m_hi <= dst) { |  | ||||||
|                 set(dst, m_hi); |  | ||||||
|                 sub1(dst); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else if (m_hi <= dst && m_lo > dst) { |  | ||||||
|             set(dst, m_hi); |  | ||||||
|             sub1(dst); |  | ||||||
|         } |  | ||||||
|         SASSERT(well_formed()); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool sls_valuation::set_random_at_most(bvect const& src, bvect& tmp, random_gen& r) { |  | ||||||
|         if (!get_at_most(src, tmp)) |  | ||||||
|             return false; |             return false; | ||||||
|         if (is_zero(tmp) || (0 == r() % 2)) |         m_lo.copy_to(nw, dst); | ||||||
|             return try_set(tmp); |         SASSERT(can_set(dst)); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool sls_valuation::set_random_at_most(bvect const& src, random_gen& r) { | ||||||
|  |         m_tmp.set_bw(bw); | ||||||
|  |         if (!get_at_most(src, m_tmp)) | ||||||
|  |             return false; | ||||||
|  | 
 | ||||||
|  |         if (is_zero(m_tmp) || (0 != r(10))) | ||||||
|  |             return try_set(m_tmp); | ||||||
| 
 | 
 | ||||||
|         set_random_below(tmp, r); |  | ||||||
|         // random value below tmp
 |         // random value below tmp
 | ||||||
|  |         set_random_below(m_tmp, r); | ||||||
|          |          | ||||||
|         if (m_lo == m_hi || is_zero(m_lo) || m_lo <= tmp) |         return (can_set(m_tmp) || get_at_most(src, m_tmp)) && try_set(m_tmp); | ||||||
|             return try_set(tmp); |  | ||||||
| 
 |  | ||||||
|         // for simplicity, bail out if we were not lucky
 |  | ||||||
|         return get_at_most(src, tmp) && try_set(tmp);   |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_valuation::set_random_at_least(bvect const& src, bvect& tmp, random_gen& r) { |     bool sls_valuation::set_random_at_least(bvect const& src, random_gen& r) { | ||||||
|         if (!get_at_least(src, tmp)) |         if (!get_at_least(src, m_tmp)) | ||||||
|             return false; |             return false; | ||||||
|         if (is_ones(tmp) || (0 == r() % 2)) | 
 | ||||||
|             return try_set(tmp); |         if (is_ones(m_tmp) || (0 != r(10))) | ||||||
|  |             return try_set(m_tmp); | ||||||
| 
 | 
 | ||||||
|         // random value at least tmp
 |         // random value at least tmp
 | ||||||
|         set_random_above(tmp, r); |         set_random_above(m_tmp, r); | ||||||
| 
 | 
 | ||||||
|         if (m_lo == m_hi || is_zero(m_hi) || m_hi > tmp) |         return (can_set(m_tmp) || get_at_least(src, m_tmp)) && try_set(m_tmp); | ||||||
|             return try_set(tmp); |  | ||||||
| 
 |  | ||||||
|         // for simplicity, bail out if we were not lucky
 |  | ||||||
|         return get_at_least(src, tmp) && try_set(tmp);         |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool sls_valuation::set_random_in_range(bvect const& lo, bvect const& hi, bvect& tmp, random_gen& r) { |     bool sls_valuation::set_random_in_range(bvect const& lo, bvect const& hi, random_gen& r) { | ||||||
|         if (0 == r() % 2) { |         bvect& tmp = m_tmp; | ||||||
|  |         if (0 == r(2)) { | ||||||
|             if (!get_at_least(lo, tmp)) |             if (!get_at_least(lo, tmp)) | ||||||
|                 return false; |                 return false; | ||||||
|             SASSERT(in_range(tmp)); |             SASSERT(in_range(tmp)); | ||||||
|  | @ -344,7 +344,7 @@ namespace bv { | ||||||
|     bool sls_valuation::set_repair(bool try_down, bvect& dst) { |     bool sls_valuation::set_repair(bool try_down, bvect& dst) { | ||||||
|         for (unsigned i = 0; i < nw; ++i) |         for (unsigned i = 0; i < nw; ++i) | ||||||
|             dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); |             dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); | ||||||
| 
 |         clear_overflow_bits(dst); | ||||||
|         repair_sign_bits(dst); |         repair_sign_bits(dst); | ||||||
|         if (in_range(dst)) { |         if (in_range(dst)) { | ||||||
|             set(eval, dst); |             set(eval, dst); | ||||||
|  | @ -409,6 +409,16 @@ namespace bv { | ||||||
|         return bw; |         return bw; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     unsigned sls_valuation::clz(bvect const& src) const { | ||||||
|  |         SASSERT(!has_overflow(src)); | ||||||
|  |         unsigned i = bw; | ||||||
|  |         for (; i-- > 0; ) | ||||||
|  |             if (!src.get(i)) | ||||||
|  |                 return bw - 1 - i; | ||||||
|  |         return bw; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     void sls_valuation::set_value(bvect& bits, rational const& n) { |     void sls_valuation::set_value(bvect& bits, rational const& n) { | ||||||
|         for (unsigned i = 0; i < bw; ++i) |         for (unsigned i = 0; i < bw; ++i) | ||||||
|             bits.set(i, n.get_bit(i)); |             bits.set(i, n.get_bit(i)); | ||||||
|  | @ -433,14 +443,22 @@ namespace bv { | ||||||
|         clear_overflow_bits(dst); |         clear_overflow_bits(dst); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool sls_valuation::set_random(random_gen& r) { | ||||||
|  |         get_variant(m_tmp, r); | ||||||
|  |         return set_repair(r(2) == 0, m_tmp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void sls_valuation::repair_sign_bits(bvect& dst) const { |     void sls_valuation::repair_sign_bits(bvect& dst) const { | ||||||
|         if (m_signed_prefix == 0) |         if (m_signed_prefix == 0) | ||||||
|             return; |             return; | ||||||
|         bool sign = dst.get(bw - 1); |         bool sign = m_signed_prefix == bw ? dst.get(bw - 1) : dst.get(bw - m_signed_prefix - 1); | ||||||
|         for (unsigned i = bw; i-- >= bw - m_signed_prefix; ) { |         for (unsigned i = bw; i-- > bw - m_signed_prefix; ) { | ||||||
|             if (dst.get(i) != sign) { |             if (dst.get(i) != sign) { | ||||||
|                 if (fixed.get(i)) { |                 if (fixed.get(i)) { | ||||||
|                     for (unsigned i = bw; i-- >= bw - m_signed_prefix; ) |                     unsigned j = bw - m_signed_prefix; | ||||||
|  |                     if (j > 0 && !fixed.get(j - 1)) | ||||||
|  |                         dst.set(j - 1, !sign); | ||||||
|  |                     for (unsigned i = bw; i-- > bw - m_signed_prefix; ) | ||||||
|                         if (!fixed.get(i)) |                         if (!fixed.get(i)) | ||||||
|                             dst.set(i, !sign); |                             dst.set(i, !sign); | ||||||
|                     return; |                     return; | ||||||
|  | @ -453,7 +471,7 @@ namespace bv { | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|     // new_bits != bits => ~fixed
 |     // new_bits != bits => ~fixed
 | ||||||
|     // 0 = (new_bits ^ bits) & fixed
 |     // 0 = (new_bits ^ bits) & fixedf
 | ||||||
|     // also check that new_bits are in range
 |     // also check that new_bits are in range
 | ||||||
|     //
 |     //
 | ||||||
|     bool sls_valuation::can_set(bvect const& new_bits) const { |     bool sls_valuation::can_set(bvect const& new_bits) const { | ||||||
|  | @ -464,24 +482,11 @@ namespace bv { | ||||||
|         return in_range(new_bits); |         return in_range(new_bits); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     unsigned sls_valuation::to_nat(unsigned max_n) { |     unsigned sls_valuation::to_nat(unsigned max_n) const { | ||||||
|  | 
 | ||||||
|         bvect const& d = m_bits; |         bvect const& d = m_bits; | ||||||
|         SASSERT(!has_overflow(d)); |         SASSERT(!has_overflow(d)); | ||||||
|         SASSERT(max_n < UINT_MAX / 2); |         return d.to_nat(max_n); | ||||||
|         unsigned p = 1; |  | ||||||
|         unsigned value = 0; |  | ||||||
|         for (unsigned i = 0; i < bw; ++i) { |  | ||||||
|             if (p >= max_n) { |  | ||||||
|                 for (unsigned j = i; j < bw; ++j) |  | ||||||
|                     if (d.get(j)) |  | ||||||
|                         return max_n; |  | ||||||
|                 return value; |  | ||||||
|             } |  | ||||||
|             if (d.get(i)) |  | ||||||
|                 value += p; |  | ||||||
|             p <<= 1; |  | ||||||
|         } |  | ||||||
|         return value; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls_valuation::shift_right(bvect& out, unsigned shift) const { |     void sls_valuation::shift_right(bvect& out, unsigned shift) const { | ||||||
|  | @ -492,14 +497,15 @@ namespace bv { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void sls_valuation::add_range(rational l, rational h) {    |     void sls_valuation::add_range(rational l, rational h) {    | ||||||
|  |         //return;
 | ||||||
|  |         //verbose_stream() << *this << " " << l << " " << h << " --> \n";
 | ||||||
| 
 | 
 | ||||||
|         l = mod(l, rational::power_of_two(bw)); |         l = mod(l, rational::power_of_two(bw)); | ||||||
|         h = mod(h, rational::power_of_two(bw)); |         h = mod(h, rational::power_of_two(bw)); | ||||||
|         if (h == l) |         if (h == l) | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         //verbose_stream() << "[" << l << ", " << h << "[\n";
 | //        verbose_stream() << *this << " " << l << " " << h << " --> ";
 | ||||||
|         //verbose_stream() << *this << "\n";
 |  | ||||||
| 
 | 
 | ||||||
|         if (m_lo == m_hi) { |         if (m_lo == m_hi) { | ||||||
|             set_value(m_lo, l); |             set_value(m_lo, l); | ||||||
|  | @ -509,32 +515,42 @@ namespace bv { | ||||||
|             auto old_lo = lo(); |             auto old_lo = lo(); | ||||||
|             auto old_hi = hi(); |             auto old_hi = hi(); | ||||||
|             if (old_lo < old_hi) { |             if (old_lo < old_hi) { | ||||||
|                 if (old_lo < l && l < old_hi) |                 if (old_lo < l && l < old_hi && old_hi <= h) | ||||||
|                     set_value(m_lo, l), |                     set_value(m_lo, l), | ||||||
|                     old_lo = l; |                     old_lo = l; | ||||||
|                 if (old_hi < h && h < old_hi) |                 if (l <= old_lo && old_lo < h && h < old_hi) | ||||||
|                     set_value(m_hi, h); |                     set_value(m_hi, h); | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 SASSERT(old_hi < old_lo); |                 SASSERT(old_hi < old_lo); | ||||||
|                 if (old_lo < l || l < old_hi) |                 if (h <= old_hi && old_lo <= l) { | ||||||
|                     set_value(m_lo, l), |                     set_value(m_lo, l); | ||||||
|                     old_lo = l; |  | ||||||
|                 if (old_lo < h && h < old_hi) |  | ||||||
|                     set_value(m_hi, h); |                     set_value(m_hi, h); | ||||||
|                 else if (old_hi < old_lo && (h < old_hi || old_lo < h)) |                 } | ||||||
|  |                 else if (old_lo <= l && l <= h) { | ||||||
|  |                     set_value(m_lo, l); | ||||||
|  |                     set_value(m_hi, h); | ||||||
|  |                 } | ||||||
|  |                 else if (old_lo + 1 == l)  | ||||||
|  |                     set_value(m_lo, l);                 | ||||||
|  |                 else if (old_hi == h + 1) | ||||||
|  |                     set_value(m_hi, h);                 | ||||||
|  |                 else if (old_hi == h && old_lo < l) | ||||||
|  |                     set_value(m_lo, l); | ||||||
|  |                 else if (old_lo == l && h < old_hi) | ||||||
|                     set_value(m_hi, h); |                     set_value(m_hi, h); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         SASSERT(!has_overflow(m_lo)); |         SASSERT(!has_overflow(m_lo)); | ||||||
|         SASSERT(!has_overflow(m_hi)); |         SASSERT(!has_overflow(m_hi)); | ||||||
| 
 | 
 | ||||||
|  |         //verbose_stream() << *this << " --> ";
 | ||||||
|  | 
 | ||||||
|         tighten_range(); |         tighten_range(); | ||||||
|  | 
 | ||||||
|  |         //verbose_stream() << *this << "\n";
 | ||||||
|         SASSERT(well_formed()); |         SASSERT(well_formed()); | ||||||
|         // verbose_stream() << *this << "\n";
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|  | @ -551,67 +567,87 @@ namespace bv { | ||||||
|     //  lo + 1 = hi -> set bits = lo
 |     //  lo + 1 = hi -> set bits = lo
 | ||||||
|     //  lo < hi, set most significant bits based on hi
 |     //  lo < hi, set most significant bits based on hi
 | ||||||
|     //
 |     //
 | ||||||
|  | 
 | ||||||
|  |     unsigned sls_valuation::diff_index(bvect const& a) const { | ||||||
|  |         unsigned index = 0; | ||||||
|  |         for (unsigned i = nw; i-- > 0; ) { | ||||||
|  |             auto diff = fixed[i] & (m_bits[i] ^ a[i]); | ||||||
|  |             if (diff != 0 && index == 0) | ||||||
|  |                 index = 1 + i * 8 * sizeof(digit_t) + log2(diff); | ||||||
|  |         } | ||||||
|  |         return index; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void sls_valuation::inf_feasible(bvect& a) const { | ||||||
|  |         unsigned lo_index = diff_index(a); | ||||||
|  |          | ||||||
|  |         if (lo_index != 0) { | ||||||
|  |             lo_index--; | ||||||
|  |             SASSERT(a.get(lo_index) != m_bits.get(lo_index)); | ||||||
|  |             SASSERT(fixed.get(lo_index)); | ||||||
|  |             for (unsigned i = 0; i <= lo_index; ++i) { | ||||||
|  |                 if (!fixed.get(i)) | ||||||
|  |                     a.set(i, false); | ||||||
|  |                 else if (fixed.get(i)) | ||||||
|  |                     a.set(i, m_bits.get(i)); | ||||||
|  |             } | ||||||
|  |             if (!a.get(lo_index)) { | ||||||
|  |                 for (unsigned i = lo_index + 1; i < bw; ++i) | ||||||
|  |                     if (!fixed.get(i) && !a.get(i)) { | ||||||
|  |                         a.set(i, true); | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void sls_valuation::sup_feasible(bvect& a) const { | ||||||
|  |         unsigned hi_index = diff_index(a); | ||||||
|  |         if (hi_index != 0) { | ||||||
|  |             hi_index--; | ||||||
|  |             SASSERT(a.get(hi_index) != m_bits.get(hi_index)); | ||||||
|  |             SASSERT(fixed.get(hi_index)); | ||||||
|  |             for (unsigned i = 0; i <= hi_index; ++i) { | ||||||
|  |                 if (!fixed.get(i)) | ||||||
|  |                     a.set(i, true); | ||||||
|  |                 else if (fixed.get(i)) | ||||||
|  |                     a.set(i, m_bits.get(i)); | ||||||
|  |             } | ||||||
|  |             if (a.get(hi_index)) { | ||||||
|  |                 for (unsigned i = hi_index + 1; i < bw; ++i) | ||||||
|  |                     if (!fixed.get(i) && a.get(i)) { | ||||||
|  |                         a.set(i, false); | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void sls_valuation::tighten_range() { |     void sls_valuation::tighten_range() { | ||||||
|          |          | ||||||
|         // verbose_stream() << "tighten " << *this << "\n";
 |  | ||||||
|         if (m_lo == m_hi) |         if (m_lo == m_hi) | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         if (!in_range(m_bits)) { |         inf_feasible(m_lo); | ||||||
|             // verbose_stream() << "not in range\n";
 |  | ||||||
|             bool compatible = true; |  | ||||||
|             for (unsigned i = 0; i < nw && compatible; ++i) |  | ||||||
|                 compatible = 0 == (fixed[i] & (m_bits[i] ^ m_lo[i])); |  | ||||||
|             //verbose_stream() << (fixed[0] & (m_bits[0] ^ m_lo[0])) << "\n";
 |  | ||||||
|             //verbose_stream() << bw << " " << m_lo[0] << " " << m_bits[0] << "\n";
 |  | ||||||
|             if (compatible) { |  | ||||||
|                 //verbose_stream() << "compatible\n";
 |  | ||||||
|                 set(m_bits, m_lo); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 bvect tmp(m_bits.nw); |  | ||||||
|                 tmp.set_bw(bw); |  | ||||||
|                 set(tmp, m_lo); |  | ||||||
|                 unsigned max_diff = bw; |  | ||||||
|                 for (unsigned i = 0; i < bw; ++i) { |  | ||||||
|                     if (fixed.get(i) && (m_bits.get(i) ^ m_lo.get(i)))  |  | ||||||
|                         max_diff = i;                     |  | ||||||
|                 } |  | ||||||
|                 SASSERT(max_diff != bw); |  | ||||||
| 
 | 
 | ||||||
|                 for (unsigned i = 0; i <= max_diff; ++i) |         bvect& hi1 = m_tmp; | ||||||
|                     tmp.set(i, fixed.get(i) && m_bits.get(i)); |         hi1.set_bw(bw); | ||||||
|  |         m_hi.copy_to(nw, hi1); | ||||||
|  |         sub1(hi1); | ||||||
|  |         sup_feasible(hi1); | ||||||
|  |         add1(hi1); | ||||||
|  |         hi1.copy_to(nw, m_hi); | ||||||
| 
 | 
 | ||||||
|                 bool found0 = false; |         if (has_range() && !in_range(m_bits))  | ||||||
|                 for (unsigned i = max_diff + 1; i < bw; ++i) { |             m_bits = m_lo; | ||||||
|                     if (found0 || m_lo.get(i) || fixed.get(i)) |  | ||||||
|                         tmp.set(i, m_lo.get(i) && fixed.get(i)); |  | ||||||
|                     else { |  | ||||||
|                         tmp.set(i, true); |  | ||||||
|                         found0 = true; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 set(m_bits, tmp); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // update lo, hi to be feasible.
 |  | ||||||
| 
 | 
 | ||||||
|         for (unsigned i = bw; i-- > 0; ) { |         if (mod(lo() + 1, rational::power_of_two(bw)) == hi()) | ||||||
|             if (!fixed.get(i)) |             for (unsigned i = 0; i < nw; ++i) | ||||||
|                 continue; |                 fixed[i] = ~0;       | ||||||
|             if (m_bits.get(i) == m_lo.get(i)) |         if (lo() < hi() && hi() < rational::power_of_two(bw - 1)) | ||||||
|                 continue; |             for (unsigned i = 0; i < bw; ++i) | ||||||
|             if (m_bits.get(i)) { |                 if (hi() < rational::power_of_two(i)) | ||||||
|                 m_lo.set(i, true); |                     fixed.set(i, true); | ||||||
|                 for (unsigned j = i; j-- > 0; ) |  | ||||||
|                     m_lo.set(j, fixed.get(j) && m_bits.get(j)); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 for (unsigned j = bw; j-- > 0; ) |  | ||||||
|                     m_lo.set(j, fixed.get(j) && m_bits.get(j)); |  | ||||||
|             } |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|          |          | ||||||
|         SASSERT(well_formed()); |         SASSERT(well_formed()); | ||||||
|     } |     } | ||||||
|  | @ -648,6 +684,4 @@ namespace bv { | ||||||
|             c += get_num_1bits(src[i]); |             c += get_num_1bits(src[i]); | ||||||
|         return c == 1; |         return c == 1; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -60,13 +60,27 @@ namespace bv { | ||||||
|             return bw; |             return bw; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         void set_zero()  { | ||||||
|  |             for (unsigned i = 0; i < nw; ++i) | ||||||
|  |                 (*this)[i] = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bvect& set_shift_right(bvect const& a, bvect const& b); | ||||||
|  |         bvect& set_shift_right(bvect const& a, unsigned shift); | ||||||
|  |         bvect& set_shift_left(bvect const& a, bvect const& b); | ||||||
|  | 
 | ||||||
|         rational get_value(unsigned nw) const; |         rational get_value(unsigned nw) const; | ||||||
| 
 | 
 | ||||||
|  |         unsigned to_nat(unsigned max_n) const; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|         friend bool operator==(bvect const& a, bvect const& b); |         friend bool operator==(bvect const& a, bvect const& b); | ||||||
|         friend bool operator<(bvect const& a, bvect const& b); |         friend bool operator<(bvect const& a, bvect const& b); | ||||||
|         friend bool operator>(bvect const& a, bvect const& b); |         friend bool operator>(bvect const& a, bvect const& b); | ||||||
|         friend bool operator<=(bvect const& a, bvect const& b); |         friend bool operator<=(bvect const& a, bvect const& b); | ||||||
|         friend bool operator>=(bvect const& a, bvect const& b); |         friend bool operator>=(bvect const& a, bvect const& b); | ||||||
|  |         friend bool operator<=(digit_t a, bvect const& b); | ||||||
|  |         friend bool operator<=(bvect const& a, digit_t b); | ||||||
|         friend std::ostream& operator<<(std::ostream& out, bvect const& v); |         friend std::ostream& operator<<(std::ostream& out, bvect const& v); | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|  | @ -96,11 +110,10 @@ namespace bv { | ||||||
|     protected: |     protected: | ||||||
|         bvect m_bits; |         bvect m_bits; | ||||||
|         bvect m_lo, m_hi;        // range assignment to bit-vector, as wrap-around interval
 |         bvect m_lo, m_hi;        // range assignment to bit-vector, as wrap-around interval
 | ||||||
|  |         bvect m_tmp; | ||||||
|         unsigned m_signed_prefix = 0; |         unsigned m_signed_prefix = 0; | ||||||
| 
 | 
 | ||||||
|         unsigned mask; |         unsigned mask; | ||||||
|         bool round_up(bvect& dst) const; |  | ||||||
|         bool round_down(bvect& dst) const; |  | ||||||
| 
 | 
 | ||||||
|         void repair_sign_bits(bvect& dst) const; |         void repair_sign_bits(bvect& dst) const; | ||||||
| 
 | 
 | ||||||
|  | @ -111,6 +124,7 @@ namespace bv { | ||||||
|         bvect fixed;                     // bit assignment and don't care bit
 |         bvect fixed;                     // bit assignment and don't care bit
 | ||||||
|         bvect eval;                      // current evaluation
 |         bvect eval;                      // current evaluation
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         sls_valuation(unsigned bw); |         sls_valuation(unsigned bw); | ||||||
| 
 | 
 | ||||||
|         void set_bw(unsigned bw); |         void set_bw(unsigned bw); | ||||||
|  | @ -127,9 +141,11 @@ namespace bv { | ||||||
|             SASSERT(in_range(m_bits)); |             SASSERT(in_range(m_bits)); | ||||||
|             if (fixed.get(i) && get_bit(i) != b) |             if (fixed.get(i) && get_bit(i) != b) | ||||||
|                 return false; |                 return false; | ||||||
|  |             m_bits.set(i, b);    | ||||||
|             eval.set(i, b); |             eval.set(i, b); | ||||||
|             if (in_range(m_bits)) |             if (in_range(m_bits)) | ||||||
|                 return true; |                 return true; | ||||||
|  |             m_bits.set(i, !b); | ||||||
|             eval.set(i, !b); |             eval.set(i, !b); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  | @ -141,6 +157,9 @@ namespace bv { | ||||||
|         rational lo() const { return m_lo.get_value(nw); } |         rational lo() const { return m_lo.get_value(nw); } | ||||||
|         rational hi() const { return m_hi.get_value(nw); } |         rational hi() const { return m_hi.get_value(nw); } | ||||||
| 
 | 
 | ||||||
|  |         unsigned diff_index(bvect const& a) const; | ||||||
|  |         void inf_feasible(bvect& a) const; | ||||||
|  |         void sup_feasible(bvect& a) const; | ||||||
| 
 | 
 | ||||||
|         void get(bvect& dst) const; |         void get(bvect& dst) const; | ||||||
|         void add_range(rational lo, rational hi); |         void add_range(rational lo, rational hi); | ||||||
|  | @ -198,6 +217,8 @@ namespace bv { | ||||||
|         // most significant bit or bw if src = 0
 |         // most significant bit or bw if src = 0
 | ||||||
|         unsigned msb(bvect const& src) const; |         unsigned msb(bvect const& src) const; | ||||||
| 
 | 
 | ||||||
|  |         unsigned clz(bvect const& src) const; | ||||||
|  | 
 | ||||||
|         bool is_power_of2(bvect const& src) const; |         bool is_power_of2(bvect const& src) const; | ||||||
| 
 | 
 | ||||||
|         // retrieve largest number at or below (above) src which is feasible
 |         // retrieve largest number at or below (above) src which is feasible
 | ||||||
|  | @ -205,13 +226,14 @@ namespace bv { | ||||||
|         bool get_at_most(bvect const& src, bvect& dst) const; |         bool get_at_most(bvect const& src, bvect& dst) const; | ||||||
|         bool get_at_least(bvect const& src, bvect& dst) const; |         bool get_at_least(bvect const& src, bvect& dst) const; | ||||||
| 
 | 
 | ||||||
|         bool set_random_at_most(bvect const& src, bvect& tmp, random_gen& r); |         bool set_random_at_most(bvect const& src, random_gen& r); | ||||||
|         bool set_random_at_least(bvect const& src, bvect& tmp, random_gen& r); |         bool set_random_at_least(bvect const& src, random_gen& r); | ||||||
|         bool set_random_in_range(bvect const& lo, bvect const& hi, bvect& tmp, random_gen& r); |         bool set_random_in_range(bvect const& lo, bvect const& hi, random_gen& r); | ||||||
| 
 | 
 | ||||||
|         bool set_repair(bool try_down, bvect& dst); |         bool set_repair(bool try_down, bvect& dst); | ||||||
|         void set_random_above(bvect& dst, random_gen& r); |         void set_random_above(bvect& dst, random_gen& r); | ||||||
|         void set_random_below(bvect& dst, random_gen& r); |         void set_random_below(bvect& dst, random_gen& r); | ||||||
|  |         bool set_random(random_gen& r); | ||||||
|         void round_down(bvect& dst, std::function<bool(bvect const&)> const& is_feasible); |         void round_down(bvect& dst, std::function<bool(bvect const&)> const& is_feasible); | ||||||
|         void round_up(bvect& dst, std::function<bool(bvect const&)> const& is_feasible); |         void round_up(bvect& dst, std::function<bool(bvect const&)> const& is_feasible); | ||||||
| 
 | 
 | ||||||
|  | @ -219,6 +241,7 @@ namespace bv { | ||||||
|         static digit_t random_bits(random_gen& r); |         static digit_t random_bits(random_gen& r); | ||||||
|         void get_variant(bvect& dst, random_gen& r) const; |         void get_variant(bvect& dst, random_gen& r) const; | ||||||
|          |          | ||||||
|  | 
 | ||||||
|         bool try_set(bvect const& src) { |         bool try_set(bvect const& src) { | ||||||
|             if (!can_set(src)) |             if (!can_set(src)) | ||||||
|                 return false; |                 return false; | ||||||
|  | @ -258,6 +281,17 @@ namespace bv { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         void add1(bvect& out) const { | ||||||
|  |             for (unsigned i = 0; i < bw; ++i) { | ||||||
|  |                 if (!out.get(i)) { | ||||||
|  |                     out.set(i, true); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                     out.set(i, false); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         void set_sub(bvect& out, bvect const& a, bvect const& b) const; |         void set_sub(bvect& out, bvect const& a, bvect const& b) const; | ||||||
|         bool set_add(bvect& out, bvect const& a, bvect const& b) const; |         bool set_add(bvect& out, bvect const& a, bvect const& b) const; | ||||||
|         bool set_mul(bvect& out, bvect const& a, bvect const& b, bool check_overflow = true) const; |         bool set_mul(bvect& out, bvect const& a, bvect const& b, bool check_overflow = true) const; | ||||||
|  | @ -288,7 +322,7 @@ namespace bv { | ||||||
|                 dst[i] = src[i]; |                 dst[i] = src[i]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         unsigned to_nat(unsigned max_n); |         unsigned to_nat(unsigned max_n) const; | ||||||
| 
 | 
 | ||||||
|         std::ostream& display(std::ostream& out) const { |         std::ostream& display(std::ostream& out) const { | ||||||
|             out << m_bits; |             out << m_bits; | ||||||
|  |  | ||||||
|  | @ -1894,6 +1894,8 @@ void cmd_context::add_declared_functions(model& mdl) { | ||||||
|     model_params p; |     model_params p; | ||||||
|     if (!p.user_functions()) |     if (!p.user_functions()) | ||||||
|         return; |         return; | ||||||
|  |     if (m_params.m_smtlib2_compliant) | ||||||
|  |         return; | ||||||
|     for (auto const& kv : m_func_decls) { |     for (auto const& kv : m_func_decls) { | ||||||
|         func_decl* f = kv.m_value.first(); |         func_decl* f = kv.m_value.first(); | ||||||
|         if (f->get_family_id() == null_family_id && !mdl.has_interpretation(f)) { |         if (f->get_family_id() == null_family_id && !mdl.has_interpretation(f)) { | ||||||
|  | @ -2066,7 +2068,10 @@ void cmd_context::complete_model(model_ref& md) const { | ||||||
|                  |                  | ||||||
|             if (m_macros.find(k, decls))  |             if (m_macros.find(k, decls))  | ||||||
|                 body = decls.find(f->get_arity(), f->get_domain()); |                 body = decls.find(f->get_arity(), f->get_domain()); | ||||||
|  |             if (body && m_params.m_smtlib2_compliant) | ||||||
|  |                 continue; | ||||||
|             sort * range = f->get_range(); |             sort * range = f->get_range(); | ||||||
|  |              | ||||||
|             if (!body) |             if (!body) | ||||||
|                 body = m().get_some_value(range); |                 body = m().get_some_value(range); | ||||||
|             if (f->get_arity() > 0) { |             if (f->get_arity() > 0) { | ||||||
|  |  | ||||||
|  | @ -393,6 +393,7 @@ public: | ||||||
|     bool external_is_used(unsigned) const; |     bool external_is_used(unsigned) const; | ||||||
|     void pop(unsigned k); |     void pop(unsigned k); | ||||||
|     unsigned num_scopes() const { return m_trail.get_num_scopes(); } |     unsigned num_scopes() const { return m_trail.get_num_scopes(); } | ||||||
|  |     trail_stack& trail() { return m_trail; } | ||||||
|     bool compare_values(lpvar j, lconstraint_kind kind, const mpq& right_side); |     bool compare_values(lpvar j, lconstraint_kind kind, const mpq& right_side); | ||||||
|     lpvar add_term(const vector<std::pair<mpq, lpvar>>& coeffs, unsigned ext_i); |     lpvar add_term(const vector<std::pair<mpq, lpvar>>& coeffs, unsigned ext_i); | ||||||
|     void register_existing_terms(); |     void register_existing_terms(); | ||||||
|  |  | ||||||
|  | @ -1062,6 +1062,8 @@ new_lemma::~new_lemma() { | ||||||
|     if (current().is_conflict()) { |     if (current().is_conflict()) { | ||||||
|         c.m_conflicts++; |         c.m_conflicts++; | ||||||
|     } |     } | ||||||
|  |     IF_VERBOSE(4, verbose_stream() << name << "\n"); | ||||||
|  |     IF_VERBOSE(4, verbose_stream() << *this << "\n"); | ||||||
|     TRACE("nla_solver", tout << name << " " << (++i) << "\n" << *this; ); |     TRACE("nla_solver", tout << name << " " << (++i) << "\n" << *this; ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1520,6 +1522,7 @@ lbool core::check() { | ||||||
|             return l_false; |             return l_false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |      | ||||||
|     if (no_effect() && should_run_bounded_nlsat())  |     if (no_effect() && should_run_bounded_nlsat())  | ||||||
|         ret = bounded_nlsat(); |         ret = bounded_nlsat(); | ||||||
|                  |                  | ||||||
|  | @ -1532,10 +1535,14 @@ lbool core::check() { | ||||||
|     if (no_effect())  |     if (no_effect())  | ||||||
|         m_divisions.check(); |         m_divisions.check(); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     if (no_effect()) { |     if (no_effect()) { | ||||||
|         std::function<void(void)> check1 = [&]() { m_order.order_lemma(); }; |         std::function<void(void)> check1 = [&]() { m_order.order_lemma(); | ||||||
|         std::function<void(void)> check2 = [&]() { m_monotone.monotonicity_lemma(); }; |         }; | ||||||
|         std::function<void(void)> check3 = [&]() { m_tangents.tangent_lemma(); }; |         std::function<void(void)> check2 = [&]() { m_monotone.monotonicity_lemma(); | ||||||
|  |         }; | ||||||
|  |         std::function<void(void)> check3 = [&]() { m_tangents.tangent_lemma(); | ||||||
|  |         }; | ||||||
|          |          | ||||||
|         std::pair<unsigned, std::function<void(void)>> checks[] =  |         std::pair<unsigned, std::function<void(void)>> checks[] =  | ||||||
|             { { 6, check1 },  |             { { 6, check1 },  | ||||||
|  |  | ||||||
|  | @ -3,6 +3,10 @@ | ||||||
|   Author: Nikolaj Bjorner, Lev Nachmanson |   Author: Nikolaj Bjorner, Lev Nachmanson | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #ifndef SINGLE_THREAD | ||||||
|  | #include <thread> | ||||||
|  | #endif | ||||||
|  | #include <fstream> | ||||||
| #include "math/lp/lar_solver.h" | #include "math/lp/lar_solver.h" | ||||||
| #include "math/lp/nra_solver.h" | #include "math/lp/nra_solver.h" | ||||||
| #include "nlsat/nlsat_solver.h" | #include "nlsat/nlsat_solver.h" | ||||||
|  | @ -11,6 +15,7 @@ | ||||||
| #include "util/map.h" | #include "util/map.h" | ||||||
| #include "util/uint_set.h" | #include "util/uint_set.h" | ||||||
| #include "math/lp/nla_core.h" | #include "math/lp/nla_core.h" | ||||||
|  | #include "smt/params/smt_params_helper.hpp" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace nra { | namespace nra { | ||||||
|  | @ -157,6 +162,23 @@ struct solver::imp { | ||||||
| 
 | 
 | ||||||
|         TRACE("nra", m_nlsat->display(tout)); |         TRACE("nra", m_nlsat->display(tout)); | ||||||
| 
 | 
 | ||||||
|  |         smt_params_helper p(m_params); | ||||||
|  |         if (p.arith_nl_log()) { | ||||||
|  |             static unsigned id = 0; | ||||||
|  |             std::stringstream strm; | ||||||
|  | 
 | ||||||
|  | #ifndef SINGLE_THREAD             | ||||||
|  |             std::thread::id this_id = std::this_thread::get_id(); | ||||||
|  |             strm << "nla_" << this_id << "." << (++id) << ".smt2"; | ||||||
|  | #else | ||||||
|  |             strm << "nla_" << (++id) << ".smt2"; | ||||||
|  | #endif | ||||||
|  |             std::ofstream out(strm.str()); | ||||||
|  |             m_nlsat->display_smt2(out); | ||||||
|  |             out << "(check-sat)\n"; | ||||||
|  |             out.close(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         lbool r = l_undef; |         lbool r = l_undef; | ||||||
|         try { |         try { | ||||||
|             r = m_nlsat->check(); |             r = m_nlsat->check(); | ||||||
|  |  | ||||||
|  | @ -2601,6 +2601,7 @@ namespace algebraic_numbers { | ||||||
|                 qm().dec(v); |                 qm().dec(v); | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|  |                 refine_until_prec(const_cast<numeral&>(a), 1); | ||||||
|                 bqm().floor(qm(), lower(a.to_algebraic()), v); |                 bqm().floor(qm(), lower(a.to_algebraic()), v); | ||||||
|             } |             } | ||||||
|             m_wrapper.set(b, v); |             m_wrapper.set(b, v); | ||||||
|  | @ -2613,6 +2614,7 @@ namespace algebraic_numbers { | ||||||
|                 qm().inc(v); |                 qm().inc(v); | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|  |                 refine_until_prec(const_cast<numeral&>(a), 1); | ||||||
|                 bqm().ceil(qm(), upper(a.to_algebraic()), v); |                 bqm().ceil(qm(), upper(a.to_algebraic()), v); | ||||||
|             } |             } | ||||||
|             m_wrapper.set(b, v); |             m_wrapper.set(b, v); | ||||||
|  |  | ||||||
|  | @ -190,6 +190,10 @@ namespace polynomial { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|  |         bool operator==(monomial const& other) const { | ||||||
|  |             return eq_proc()(this, &other); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); } |         static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); } | ||||||
|          |          | ||||||
|         monomial(unsigned id, unsigned sz, power const * pws, unsigned h): |         monomial(unsigned id, unsigned sz, power const * pws, unsigned h): | ||||||
|  | @ -3221,9 +3225,16 @@ namespace polynomial { | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         bool_vector  m_found_vars; |         bool_vector  m_found_vars; | ||||||
|         void vars(polynomial const * p, var_vector & xs) { |         void begin_vars_incremental() { | ||||||
|             xs.reset(); |  | ||||||
|             m_found_vars.reserve(num_vars(), false); |             m_found_vars.reserve(num_vars(), false); | ||||||
|  |         } | ||||||
|  |         void end_vars_incremental(var_vector& xs) { | ||||||
|  |             // reset m_found_vars
 | ||||||
|  |             unsigned sz = xs.size(); | ||||||
|  |             for (unsigned i = 0; i < sz; i++) | ||||||
|  |                 m_found_vars[xs[i]] = false; | ||||||
|  |         } | ||||||
|  |         void vars(polynomial const * p, var_vector & xs) { | ||||||
|             unsigned sz = p->size(); |             unsigned sz = p->size(); | ||||||
|             for (unsigned i = 0; i < sz; i++) { |             for (unsigned i = 0; i < sz; i++) { | ||||||
|                 monomial * m = p->m(i); |                 monomial * m = p->m(i); | ||||||
|  | @ -3236,10 +3247,6 @@ namespace polynomial { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             // reset m_found_vars
 |  | ||||||
|             sz = xs.size(); |  | ||||||
|             for (unsigned i = 0; i < sz; i++) |  | ||||||
|                 m_found_vars[xs[i]] = false; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         typedef sbuffer<power, 32>    power_buffer; |         typedef sbuffer<power, 32>    power_buffer; | ||||||
|  | @ -6046,6 +6053,47 @@ namespace polynomial { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|         |         | ||||||
|  |         bool ge(polynomial const* p, polynomial const* q) { | ||||||
|  |             unsigned sz1 = p->size(); | ||||||
|  |             unsigned sz2 = q->size(); | ||||||
|  |             unsigned i = 0, j = 0; | ||||||
|  |             while (i < sz1 || j < sz2) { | ||||||
|  |                 auto * m1 = i < sz1 ? p->m(i) : q->m(j); | ||||||
|  |                 auto & a1 = i < sz1 ? p->a(i) : q->a(j); | ||||||
|  |                 auto * m2 = j < sz2 ? q->m(j) : p->m(i); | ||||||
|  |                 auto & a2 = j < sz2 ? q->a(j) : p->a(i); | ||||||
|  | 
 | ||||||
|  |                 if (i < sz1 && j == sz2 && m1->is_unit()) { | ||||||
|  |                     if (!m_manager.is_pos(a1)) | ||||||
|  |                         return false; | ||||||
|  |                     ++i; | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (i == sz1 && j < sz2 && m2->is_unit()) { | ||||||
|  |                     if (!m_manager.is_neg(a2)) | ||||||
|  |                         return false; | ||||||
|  |                     ++j; | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (i == sz1 || j == sz2) | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 if (!(*m1 == *m2)) { | ||||||
|  |                     if (m_manager.is_pos(a1) && m1->is_square()) { | ||||||
|  |                         ++i; | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 if (!m_manager.ge(a1, a2)) | ||||||
|  |                     return false; | ||||||
|  |                 ++i, ++j;                | ||||||
|  |             } | ||||||
|  |             return i == sz1 && j == sz2;            | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // Functor used to compute the maximal degree of each variable in a polynomial p.
 |         // Functor used to compute the maximal degree of each variable in a polynomial p.
 | ||||||
|         class var_max_degree { |         class var_max_degree { | ||||||
|             unsigned_vector    m_max_degree; |             unsigned_vector    m_max_degree; | ||||||
|  | @ -6269,6 +6317,27 @@ namespace polynomial { | ||||||
|             return R.mk(); |             return R.mk(); | ||||||
|         }         |         }         | ||||||
| 
 | 
 | ||||||
|  |         // x*q = p
 | ||||||
|  |         // 
 | ||||||
|  |         // md = degree of x in p
 | ||||||
|  |         // P = m0 + ...
 | ||||||
|  |         // m0 = x^dm*m1
 | ||||||
|  |         // m1 * p^dm * q^{md - dm}  
 | ||||||
|  |         // P' = m1 + ...
 | ||||||
|  |         // property would be that x*q = p => P > 0 <=> P' > 0
 | ||||||
|  |         // requires that q > 0
 | ||||||
|  |         // Reasoning:
 | ||||||
|  |         //    P > 0 
 | ||||||
|  |         // <=> { since q > 0 }
 | ||||||
|  |         //    q^md * P > 0
 | ||||||
|  |         // <=>
 | ||||||
|  |         //    q^md*x^dm*m0 + .. > 0
 | ||||||
|  |         // <=>
 | ||||||
|  |         //    q^{md-dm}*(xq)^dm*m0 + ... > 0
 | ||||||
|  |         // <=>
 | ||||||
|  |         //    q^{md-dm}*p^dm + .. > 0
 | ||||||
|  |         // <=>
 | ||||||
|  |         //    P' > 0
 | ||||||
|         void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { |         void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { | ||||||
|             unsigned md = degree(r, x); |             unsigned md = degree(r, x); | ||||||
|             if (md == 0) { |             if (md == 0) { | ||||||
|  | @ -7228,13 +7297,33 @@ namespace polynomial { | ||||||
|         return m_imp->is_nonneg(p); |         return m_imp->is_nonneg(p); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool manager::ge(polynomial const* p, polynomial const* q) { | ||||||
|  |         return m_imp->ge(p, q); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     void manager::rename(unsigned sz, var const * xs) { |     void manager::rename(unsigned sz, var const * xs) { | ||||||
|         return m_imp->rename(sz, xs); |         return m_imp->rename(sz, xs); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void manager::vars(polynomial const * p, var_vector & xs) { |     void manager::vars(polynomial const * p, var_vector & xs) { | ||||||
|  |         xs.reset(); | ||||||
|  |         m_imp->begin_vars_incremental(); | ||||||
|  |         m_imp->vars(p, xs); | ||||||
|  |         m_imp->end_vars_incremental(xs); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void manager::vars_incremental(polynomial const * p, var_vector & xs) { | ||||||
|         m_imp->vars(p, xs); |         m_imp->vars(p, xs); | ||||||
|     } |     } | ||||||
|  |     void manager::begin_vars_incremental() { | ||||||
|  |         m_imp->begin_vars_incremental(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void manager::end_vars_incremental(var_vector & xs) { | ||||||
|  |         m_imp->end_vars_incremental(xs);         | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     polynomial * manager::substitute(polynomial const * p, var2mpq const & x2v) { |     polynomial * manager::substitute(polynomial const * p, var2mpq const & x2v) { | ||||||
|         return m_imp->substitute(p, x2v); |         return m_imp->substitute(p, x2v); | ||||||
|  | @ -7293,17 +7382,20 @@ namespace polynomial { | ||||||
|         return m_imp->eval(p, x2v, r); |         return m_imp->eval(p, x2v, r); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void manager::display(std::ostream & out, monomial const * m, display_var_proc const & proc, bool user_star) const { |     std::ostream& manager::display(std::ostream & out, monomial const * m, display_var_proc const & proc, bool user_star) const { | ||||||
|         m->display(out, proc, user_star); |         m->display(out, proc, user_star); | ||||||
|  |         return out; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void manager::display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) const { |     std::ostream& manager::display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) const { | ||||||
|         SASSERT(m_imp->consistent_coeffs(p)); |         SASSERT(m_imp->consistent_coeffs(p)); | ||||||
|         p->display(out, m_imp->m_manager, proc, use_star); |         p->display(out, m_imp->m_manager, proc, use_star); | ||||||
|  |         return out; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void manager::display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc) const { |     std::ostream& manager::display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc) const { | ||||||
|         p->display_smt2(out, m_imp->m_manager, proc); |         p->display_smt2(out, m_imp->m_manager, proc); | ||||||
|  |         return out; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -921,6 +921,13 @@ namespace polynomial { | ||||||
|         */ |         */ | ||||||
|         bool is_nonneg(polynomial const * p); |         bool is_nonneg(polynomial const * p); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |            \brief Return true if p is always greater or equal to q. | ||||||
|  |            This is an incomplete check | ||||||
|  |         */ | ||||||
|  |         bool ge(polynomial const* p, polynomial const* q); | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|            \brief Make sure the monomials in p are sorted using lexicographical order. |            \brief Make sure the monomials in p are sorted using lexicographical order. | ||||||
|            Remark: the maximal monomial is at position 0. |            Remark: the maximal monomial is at position 0. | ||||||
|  | @ -931,6 +938,9 @@ namespace polynomial { | ||||||
|            \brief Collect variables that occur in p into xs |            \brief Collect variables that occur in p into xs | ||||||
|         */ |         */ | ||||||
|         void vars(polynomial const * p, var_vector & xs); |         void vars(polynomial const * p, var_vector & xs); | ||||||
|  |         void vars_incremental(polynomial const * p, var_vector & xs); | ||||||
|  |         void begin_vars_incremental(); | ||||||
|  |         void end_vars_incremental(var_vector & xs); | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|            \brief Evaluate polynomial p using the assignment [x_1 -> v_1, ..., x_n -> v_n]. |            \brief Evaluate polynomial p using the assignment [x_1 -> v_1, ..., x_n -> v_n]. | ||||||
|  | @ -1019,15 +1029,14 @@ namespace polynomial { | ||||||
|         */ |         */ | ||||||
|         void exact_pseudo_division_mod_d(polynomial const * p, polynomial const * q, var x, var2degree const & x2d, polynomial_ref & Q, polynomial_ref & R); |         void exact_pseudo_division_mod_d(polynomial const * p, polynomial const * q, var x, var2degree const & x2d, polynomial_ref & Q, polynomial_ref & R); | ||||||
| 
 | 
 | ||||||
|         void display(std::ostream & out, monomial const * m, display_var_proc const & proc = display_var_proc(), bool use_star = true) const; |         std::ostream& display(std::ostream & out, monomial const * m, display_var_proc const & proc = display_var_proc(), bool use_star = true) const; | ||||||
| 
 | 
 | ||||||
|         void display(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc(), bool use_star = false) const; |         std::ostream& display(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc(), bool use_star = false) const; | ||||||
| 
 | 
 | ||||||
|         void display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc()) const; |         std::ostream& display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc()) const; | ||||||
| 
 | 
 | ||||||
|         friend std::ostream & operator<<(std::ostream & out, polynomial_ref const & p) { |         friend std::ostream & operator<<(std::ostream & out, polynomial_ref const & p) { | ||||||
|             p.m().display(out, p); |             return p.m().display(out, p); | ||||||
|             return out; |  | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,7 +25,10 @@ namespace nlsat { | ||||||
|         m_size(sz), |         m_size(sz), | ||||||
|         m_capacity(sz), |         m_capacity(sz), | ||||||
|         m_learned(learned), |         m_learned(learned), | ||||||
|         m_activity(0), |         m_active(false), | ||||||
|  |         m_removed(false), | ||||||
|  |         m_marked(false), | ||||||
|  |         m_var_hash(0), | ||||||
|         m_assumptions(as) { |         m_assumptions(as) { | ||||||
|         for (unsigned i = 0; i < sz; i++) { |         for (unsigned i = 0; i < sz; i++) { | ||||||
|             m_lits[i] = lits[i]; |             m_lits[i] = lits[i]; | ||||||
|  |  | ||||||
|  | @ -29,7 +29,10 @@ namespace nlsat { | ||||||
|         unsigned         m_size; |         unsigned         m_size; | ||||||
|         unsigned         m_capacity:31; |         unsigned         m_capacity:31; | ||||||
|         unsigned         m_learned:1; |         unsigned         m_learned:1; | ||||||
|         unsigned         m_activity; |         unsigned         m_active:1; | ||||||
|  |         unsigned         m_removed:1; | ||||||
|  |         unsigned         m_marked:1; | ||||||
|  |         unsigned         m_var_hash; | ||||||
|         assumption_set   m_assumptions; |         assumption_set   m_assumptions; | ||||||
|         literal          m_lits[0]; |         literal          m_lits[0]; | ||||||
|         static size_t get_obj_size(unsigned num_lits) { return sizeof(clause) + num_lits * sizeof(literal); } |         static size_t get_obj_size(unsigned num_lits) { return sizeof(clause) + num_lits * sizeof(literal); } | ||||||
|  | @ -46,9 +49,15 @@ namespace nlsat { | ||||||
|         literal const * begin() const { return m_lits; } |         literal const * begin() const { return m_lits; } | ||||||
|         literal const * end() const { return m_lits + m_size; } |         literal const * end() const { return m_lits + m_size; } | ||||||
|         literal const * data() const { return m_lits; } |         literal const * data() const { return m_lits; } | ||||||
|         void inc_activity() { m_activity++; } |         void set_active(bool b) { m_active = b; } | ||||||
|         void set_activity(unsigned v) { m_activity = v; } |         bool is_active() const { return m_active; } | ||||||
|         unsigned get_activity() const { return m_activity; } |         void set_removed() { m_removed = true; } | ||||||
|  |         bool is_removed() const { return m_removed; } | ||||||
|  |         unsigned var_hash() const { return m_var_hash; } | ||||||
|  |         void set_var_hash(unsigned h) { m_var_hash = h; } | ||||||
|  |         bool is_marked() const { return m_marked; } | ||||||
|  |         void mark() { m_marked = true; } | ||||||
|  |         void unmark() { m_marked = false; } | ||||||
|         bool contains(literal l) const; |         bool contains(literal l) const; | ||||||
|         bool contains(bool_var v) const; |         bool contains(bool_var v) const; | ||||||
|         void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; } } |         void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; } } | ||||||
|  |  | ||||||
|  | @ -277,11 +277,14 @@ namespace nlsat { | ||||||
|             } |             } | ||||||
|              |              | ||||||
|         }; |         }; | ||||||
|         void add_zero_assumption(polynomial_ref & p) { | 
 | ||||||
|  |         void add_zero_assumption(polynomial_ref& p) { | ||||||
|             // If p is of the form p1^n1 * ... * pk^nk,
 |             // If p is of the form p1^n1 * ... * pk^nk,
 | ||||||
|             // then only the factors that are zero in the current interpretation needed to be considered.
 |             // then only the factors that are zero in the current interpretation needed to be considered.
 | ||||||
|             // I don't want to create a nested conjunction in the clause. 
 |             // I don't want to create a nested conjunction in the clause. 
 | ||||||
|             // Then, I assert p_i1 * ... * p_im  != 0
 |             // Then, I assert p_i1 * ... * p_im  != 0
 | ||||||
|  |             bool is_linear = true; | ||||||
|  |             unsigned x = max_var(p); | ||||||
|             { |             { | ||||||
|                 restore_factors _restore(m_factors, m_factors_save); |                 restore_factors _restore(m_factors, m_factors_save); | ||||||
|                 factor(p, m_factors); |                 factor(p, m_factors); | ||||||
|  | @ -294,10 +297,33 @@ namespace nlsat { | ||||||
|                     if (is_zero(sign(f))) { |                     if (is_zero(sign(f))) { | ||||||
|                         m_zero_fs.push_back(m_factors.get(i)); |                         m_zero_fs.push_back(m_factors.get(i)); | ||||||
|                         m_is_even.push_back(false); |                         m_is_even.push_back(false); | ||||||
|  |                         is_linear &= m_pm.degree(f, x) <= 1; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             if (!is_linear) { | ||||||
|  |                 scoped_anum_vector& roots = m_roots_tmp; | ||||||
|  |                 roots.reset(); | ||||||
|  |                 m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots); | ||||||
|  |                 unsigned num_roots = roots.size(); | ||||||
|  |                 if (num_roots > 0) { | ||||||
|  |                     anum const& x_val = m_assignment.value(x); | ||||||
|  |                     for (unsigned i = 0; i < num_roots; i++) { | ||||||
|  |                         int s = m_am.compare(x_val, roots[i]); | ||||||
|  |                         if (s != 0) | ||||||
|  |                             continue; | ||||||
|  |                         TRACE("nlsat_explain", tout << "adding (zero assumption) root " << "\n"); | ||||||
|  |                         add_root_literal(atom::ROOT_EQ, x, i + 1, p); | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                     display(verbose_stream() << "polynomial ", p); | ||||||
|  |                     m_solver.display(verbose_stream()); | ||||||
|  |                     UNREACHABLE(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             SASSERT(!m_zero_fs.empty()); // one of the factors must be zero in the current interpretation, since p is zero in it.
 |             SASSERT(!m_zero_fs.empty()); // one of the factors must be zero in the current interpretation, since p is zero in it.
 | ||||||
|  | 
 | ||||||
|             literal l = m_solver.mk_ineq_literal(atom::EQ, m_zero_fs.size(), m_zero_fs.data(), m_is_even.data()); |             literal l = m_solver.mk_ineq_literal(atom::EQ, m_zero_fs.size(), m_zero_fs.data(), m_is_even.data()); | ||||||
|             l.neg(); |             l.neg(); | ||||||
|             TRACE("nlsat_explain", tout << "adding (zero assumption) literal:\n"; display(tout, l); tout << "\n";); |             TRACE("nlsat_explain", tout << "adding (zero assumption) literal:\n"; display(tout, l); tout << "\n";); | ||||||
|  | @ -649,6 +675,52 @@ namespace nlsat { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         void add_zero_assumption_on_factor(polynomial_ref& f) { | ||||||
|  |             display(std::cout << "zero factors \n", f);  | ||||||
|  |         } | ||||||
|  |         // this function also explains the value 0, if met
 | ||||||
|  |         bool coeffs_are_zeroes(polynomial_ref &s) { | ||||||
|  |             restore_factors _restore(m_factors, m_factors_save); | ||||||
|  |             factor(s, m_factors); | ||||||
|  |             unsigned num_factors = m_factors.size(); | ||||||
|  |             m_zero_fs.reset(); | ||||||
|  |             m_is_even.reset(); | ||||||
|  |             polynomial_ref f(m_pm); | ||||||
|  |             bool have_zero = false; | ||||||
|  |             for (unsigned i = 0; i < num_factors; i++) { | ||||||
|  |                 f = m_factors.get(i); | ||||||
|  |               //  std::cout << "f=";display(std::cout, f) << "\n";
 | ||||||
|  |                 if (coeffs_are_zeroes_in_factor(f)) { | ||||||
|  |                     have_zero = true; | ||||||
|  |                     break; | ||||||
|  |                 }  | ||||||
|  |             } | ||||||
|  |             if (!have_zero) | ||||||
|  |                 return false; | ||||||
|  |             var x = max_var(f); | ||||||
|  |             unsigned n = degree(f, x); | ||||||
|  |             auto c = polynomial_ref(this->m_pm); | ||||||
|  |             for (unsigned j = 0; j <= n; j++) { | ||||||
|  |                 c = m_pm.coeff(s, x, j); | ||||||
|  |                 SASSERT(sign(c) == 0); | ||||||
|  |                 ensure_sign(c); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  |         bool coeffs_are_zeroes_in_factor(polynomial_ref & s) { | ||||||
|  |             var x = max_var(s); | ||||||
|  |             unsigned n = degree(s, x); | ||||||
|  |             auto c = polynomial_ref(this->m_pm); | ||||||
|  |             for (unsigned j = 0; j <= n; j++) { | ||||||
|  |                 c = m_pm.coeff(s, x, j); | ||||||
|  |                 if (sign(c) != 0) | ||||||
|  |                     return false; | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|            \brief Add v-psc(p, q, x) into m_todo |            \brief Add v-psc(p, q, x) into m_todo | ||||||
|         */ |         */ | ||||||
|  | @ -1022,12 +1094,12 @@ namespace nlsat { | ||||||
|             if (x < max_x) |             if (x < max_x) | ||||||
|                 add_cell_lits(ps, x); |                 add_cell_lits(ps, x); | ||||||
|             while (true) { |             while (true) { | ||||||
|  |                 TRACE("nlsat_explain", tout << "project loop, processing var "; display_var(tout, x); tout << "\npolynomials\n"; | ||||||
|  |                       display(tout, ps); tout << "\n";); | ||||||
|                 if (all_univ(ps, x) && m_todo.empty()) { |                 if (all_univ(ps, x) && m_todo.empty()) { | ||||||
|                     m_todo.reset(); |                     m_todo.reset(); | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 TRACE("nlsat_explain", tout << "project loop, processing var "; display_var(tout, x); tout << "\npolynomials\n"; |  | ||||||
|                       display(tout, ps); tout << "\n";); |  | ||||||
|                 add_lc(ps, x); |                 add_lc(ps, x); | ||||||
|                 psc_discriminant(ps, x); |                 psc_discriminant(ps, x); | ||||||
|                 psc_resultant(ps, x); |                 psc_resultant(ps, x); | ||||||
|  | @ -1672,7 +1744,16 @@ namespace nlsat { | ||||||
|                     solve_eq(x, eq_index, ps); |                     solve_eq(x, eq_index, ps); | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     project_pairs(x, eq_index, ps); |                     add_zero_assumption(p); | ||||||
|  | 
 | ||||||
|  |                     for (unsigned j = 0; j < ps.size(); ++j) { | ||||||
|  |                         if (j == eq_index) | ||||||
|  |                             continue; | ||||||
|  |                         p = ps.get(j); | ||||||
|  |                         int s = sign(p); | ||||||
|  |                         atom::kind k = (s == 0)?(atom::EQ):((s < 0)?(atom::LT):(atom::GT)); | ||||||
|  |                         add_simple_assumption(k, p, false); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -254,6 +254,8 @@ namespace nlsat { | ||||||
| 
 | 
 | ||||||
|         std::ostream& display_smt2(std::ostream & out, literal_vector const& ls) const; |         std::ostream& display_smt2(std::ostream & out, literal_vector const& ls) const; | ||||||
| 
 | 
 | ||||||
|  |                 std::ostream& display_smt2(std::ostream & out) const; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|            \brief Display variable |            \brief Display variable | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ def_module_params('sls', | ||||||
|                   description='Experimental Stochastic Local Search Solver (for QFBV only).', |                   description='Experimental Stochastic Local Search Solver (for QFBV only).', | ||||||
|                   params=(max_memory_param(), |                   params=(max_memory_param(), | ||||||
|                         ('max_restarts', UINT, UINT_MAX, 'maximum number of restarts'), |                         ('max_restarts', UINT, UINT_MAX, 'maximum number of restarts'), | ||||||
|  | 			('max_repairs', UINT, 1000, 'maximum number of repairs before restart'), | ||||||
|                         ('walksat', BOOL, 1, 'use walksat assertion selection (instead of gsat)'), |                         ('walksat', BOOL, 1, 'use walksat assertion selection (instead of gsat)'), | ||||||
|                         ('walksat_ucb', BOOL, 1, 'use bandit heuristic for walksat assertion selection (instead of random)'), |                         ('walksat_ucb', BOOL, 1, 'use bandit heuristic for walksat assertion selection (instead of random)'), | ||||||
|                         ('walksat_ucb_constant', DOUBLE, 20.0, 'the ucb constant c in the term score + c * f(touched)'), |                         ('walksat_ucb_constant', DOUBLE, 20.0, 'the ucb constant c in the term score + c * f(touched)'), | ||||||
|  |  | ||||||
|  | @ -480,8 +480,10 @@ namespace qe { | ||||||
|                 num_scopes = 2*(level()/2); |                 num_scopes = 2*(level()/2); | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 SASSERT(clevel.max() + 2 <= level()); |                 if (clevel.max() + 2 <= level())                     | ||||||
|                 num_scopes = level() - clevel.max(); |                     num_scopes = level() - clevel.max(); | ||||||
|  |                 else | ||||||
|  |                     num_scopes = 2; // the projection contains auxiliary variables from root objects.
 | ||||||
|                 SASSERT(num_scopes >= 2); |                 SASSERT(num_scopes >= 2); | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |  | ||||||
|  | @ -1314,7 +1314,7 @@ namespace sat { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool solver::should_cancel() { |     bool solver::should_cancel() { | ||||||
|         if (limit_reached() || memory_exceeded()) { |         if (limit_reached() || memory_exceeded() || m_solver_canceled) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|         if (m_config.m_restart_max <= m_restarts) { |         if (m_config.m_restart_max <= m_restarts) { | ||||||
|  | @ -1959,6 +1959,7 @@ namespace sat { | ||||||
| 
 | 
 | ||||||
|     void solver::init_search() { |     void solver::init_search() { | ||||||
|         m_model_is_current        = false; |         m_model_is_current        = false; | ||||||
|  |         m_solver_canceled         = false; | ||||||
|         m_phase_counter           = 0; |         m_phase_counter           = 0; | ||||||
|         m_search_state            = s_unsat; |         m_search_state            = s_unsat; | ||||||
|         m_search_unsat_conflicts  = m_config.m_search_unsat_conflicts; |         m_search_unsat_conflicts  = m_config.m_search_unsat_conflicts; | ||||||
|  |  | ||||||
|  | @ -177,6 +177,7 @@ namespace sat { | ||||||
|         clause_wrapper_vector   m_clauses_to_reinit; |         clause_wrapper_vector   m_clauses_to_reinit; | ||||||
|         std::string             m_reason_unknown; |         std::string             m_reason_unknown; | ||||||
|         bool                    m_trim = false; |         bool                    m_trim = false; | ||||||
|  |         bool                    m_solver_canceled = false; | ||||||
| 
 | 
 | ||||||
|         visit_helper            m_visited; |         visit_helper            m_visited; | ||||||
| 
 | 
 | ||||||
|  | @ -287,6 +288,7 @@ namespace sat { | ||||||
|         random_gen& rand() { return m_rand; } |         random_gen& rand() { return m_rand; } | ||||||
| 
 | 
 | ||||||
|         void set_trim() { m_trim = true; } |         void set_trim() { m_trim = true; } | ||||||
|  |         void set_canceled() { m_solver_canceled = true; } | ||||||
| 
 | 
 | ||||||
|     protected: |     protected: | ||||||
|         void reset_var(bool_var v, bool ext, bool dvar); |         void reset_var(bool_var v, bool ext, bool dvar); | ||||||
|  |  | ||||||
|  | @ -197,10 +197,16 @@ public: | ||||||
|         case l_false: |         case l_false: | ||||||
|             extract_core(); |             extract_core(); | ||||||
|             break; |             break; | ||||||
|         default: |         default: { | ||||||
|  |             auto* ext = get_euf(); | ||||||
|  |             if (ext && ext->get_sls_model()) { | ||||||
|  |                 r = l_true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|             set_reason_unknown(m_solver.get_reason_unknown()); |             set_reason_unknown(m_solver.get_reason_unknown()); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         } | ||||||
|         return r; |         return r; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -576,6 +582,7 @@ private: | ||||||
|     void add_assumption(expr* a) { |     void add_assumption(expr* a) { | ||||||
|         init_goal2sat(); |         init_goal2sat(); | ||||||
|         m_dep.insert(a, m_goal2sat.internalize(a)); |         m_dep.insert(a, m_goal2sat.internalize(a)); | ||||||
|  |         get_euf()->add_assertion(a); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void internalize_assumptions(expr_ref_vector const& asms) {      |     void internalize_assumptions(expr_ref_vector const& asms) {      | ||||||
|  | @ -632,6 +639,11 @@ private: | ||||||
|     void get_model_core(model_ref & mdl) override { |     void get_model_core(model_ref & mdl) override { | ||||||
|         TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); |         TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); | ||||||
|         mdl = nullptr; |         mdl = nullptr; | ||||||
|  |         auto ext = get_euf(); | ||||||
|  |         if (ext) | ||||||
|  |             mdl = ext->get_sls_model(); | ||||||
|  |         if (mdl) | ||||||
|  |             return; | ||||||
|         if (!m_solver.model_is_current())  |         if (!m_solver.model_is_current())  | ||||||
|             return; |             return; | ||||||
|         if (m_fmls.size() > m_qhead) |         if (m_fmls.size() > m_qhead) | ||||||
|  |  | ||||||
|  | @ -525,4 +525,8 @@ namespace euf { | ||||||
|         return n; |         return n; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void solver::add_assertion(expr* f) { | ||||||
|  |         m_assertions.push_back(f); | ||||||
|  |         m_trail.push(push_back_vector(m_assertions)); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ Author: | ||||||
| #include "ast/ast_pp.h" | #include "ast/ast_pp.h" | ||||||
| #include "ast/ast_ll_pp.h" | #include "ast/ast_ll_pp.h" | ||||||
| #include "sat/smt/euf_solver.h" | #include "sat/smt/euf_solver.h" | ||||||
|  | #include "sat/smt/sls_solver.h" | ||||||
| #include "model/value_factory.h" | #include "model/value_factory.h" | ||||||
| 
 | 
 | ||||||
| namespace euf { | namespace euf { | ||||||
|  | @ -67,6 +68,14 @@ namespace euf { | ||||||
|         m_qmodel = mdl; |         m_qmodel = mdl; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     model_ref solver::get_sls_model() { | ||||||
|  |         model_ref mdl; | ||||||
|  |         auto s = get_solver(m.mk_family_id("sls"), nullptr); | ||||||
|  |         if (s) | ||||||
|  |             mdl = dynamic_cast<sls::solver*>(s)->get_model(); | ||||||
|  |         return mdl; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void solver::update_model(model_ref& mdl, bool validate) { |     void solver::update_model(model_ref& mdl, bool validate) { | ||||||
|         TRACE("model", tout << "create model\n";); |         TRACE("model", tout << "create model\n";); | ||||||
|         if (m_qmodel) { |         if (m_qmodel) { | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ Author: | ||||||
| #include "sat/smt/q_solver.h" | #include "sat/smt/q_solver.h" | ||||||
| #include "sat/smt/fpa_solver.h" | #include "sat/smt/fpa_solver.h" | ||||||
| #include "sat/smt/dt_solver.h" | #include "sat/smt/dt_solver.h" | ||||||
|  | #include "sat/smt/sls_solver.h" | ||||||
| #include "sat/smt/recfun_solver.h" | #include "sat/smt/recfun_solver.h" | ||||||
| #include "sat/smt/specrel_solver.h" | #include "sat/smt/specrel_solver.h" | ||||||
| 
 | 
 | ||||||
|  | @ -55,6 +56,7 @@ namespace euf { | ||||||
|         m_smt_proof_checker(m, p), |         m_smt_proof_checker(m, p), | ||||||
|         m_clause(m),        |         m_clause(m),        | ||||||
|         m_expr_args(m), |         m_expr_args(m), | ||||||
|  |         m_assertions(m), | ||||||
|         m_values(m) |         m_values(m) | ||||||
|     { |     { | ||||||
|         updt_params(p); |         updt_params(p); | ||||||
|  | @ -78,6 +80,7 @@ namespace euf { | ||||||
|             }; |             }; | ||||||
|             m_egraph.set_on_merge(on_merge); |             m_egraph.set_on_merge(on_merge); | ||||||
|         } |         } | ||||||
|  |          | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::updt_params(params_ref const& p) { |     void solver::updt_params(params_ref const& p) { | ||||||
|  | @ -187,6 +190,8 @@ namespace euf { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::init_search() {    |     void solver::init_search() {    | ||||||
|  |         if (get_config().m_sls_enable) | ||||||
|  |             add_solver(alloc(sls::solver, *this)); | ||||||
|         TRACE("before_search", s().display(tout);); |         TRACE("before_search", s().display(tout);); | ||||||
|         m_reason_unknown.clear(); |         m_reason_unknown.clear(); | ||||||
|         for (auto* s : m_solvers) |         for (auto* s : m_solvers) | ||||||
|  | @ -666,6 +671,8 @@ namespace euf { | ||||||
|             return sat::check_result::CR_GIVEUP;   |             return sat::check_result::CR_GIVEUP;   | ||||||
|         if (m_qsolver && m_config.m_arith_ignore_int) |         if (m_qsolver && m_config.m_arith_ignore_int) | ||||||
|             return sat::check_result::CR_GIVEUP;  |             return sat::check_result::CR_GIVEUP;  | ||||||
|  |         for (auto s : m_solvers) | ||||||
|  |             s->finalize(); | ||||||
|         return sat::check_result::CR_DONE; |         return sat::check_result::CR_DONE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -155,6 +155,7 @@ namespace euf { | ||||||
|         scoped_ptr_vector<th_solver>     m_solvers; |         scoped_ptr_vector<th_solver>     m_solvers; | ||||||
|         ptr_vector<th_solver>            m_id2solver; |         ptr_vector<th_solver>            m_id2solver; | ||||||
|          |          | ||||||
|  | 
 | ||||||
|         constraint* m_conflict = nullptr; |         constraint* m_conflict = nullptr; | ||||||
|         constraint* m_eq = nullptr; |         constraint* m_eq = nullptr; | ||||||
| 
 | 
 | ||||||
|  | @ -173,6 +174,7 @@ namespace euf { | ||||||
|         symbol                           m_smt = symbol("smt");             |         symbol                           m_smt = symbol("smt");             | ||||||
|         expr_ref_vector                  m_clause; |         expr_ref_vector                  m_clause; | ||||||
|         expr_ref_vector                  m_expr_args; |         expr_ref_vector                  m_expr_args; | ||||||
|  |         expr_ref_vector                  m_assertions; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         // internalization
 |         // internalization
 | ||||||
|  | @ -482,6 +484,10 @@ namespace euf { | ||||||
|         bool enable_ackerman_axioms(expr* n) const; |         bool enable_ackerman_axioms(expr* n) const; | ||||||
|         bool is_fixed(euf::enode* n, expr_ref& val, sat::literal_vector& explain); |         bool is_fixed(euf::enode* n, expr_ref& val, sat::literal_vector& explain); | ||||||
| 
 | 
 | ||||||
|  |         void add_assertion(expr* f); | ||||||
|  |         expr_ref_vector const& get_assertions() { return m_assertions; } | ||||||
|  |         model_ref get_sls_model(); | ||||||
|  | 
 | ||||||
|         // relevancy
 |         // relevancy
 | ||||||
| 
 | 
 | ||||||
|         bool relevancy_enabled() const { return m_relevancy.enabled(); } |         bool relevancy_enabled() const { return m_relevancy.enabled(); } | ||||||
|  |  | ||||||
|  | @ -50,6 +50,7 @@ namespace intblast { | ||||||
|         sat::literal lit = expr2literal(e); |         sat::literal lit = expr2literal(e); | ||||||
|         if (sign) |         if (sign) | ||||||
|             lit.neg(); |             lit.neg(); | ||||||
|  |         TRACE("bv", tout << mk_pp(e, m) << " -> " << literal2expr(lit) << "\n"); | ||||||
|         return lit; |         return lit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -102,6 +103,7 @@ namespace intblast { | ||||||
|             set_translated(e, m.mk_eq(umod(x, 0), a.mk_int(0))); |             set_translated(e, m.mk_eq(umod(x, 0), a.mk_int(0))); | ||||||
|         } |         } | ||||||
|         m_preds.push_back(e); |         m_preds.push_back(e); | ||||||
|  |         TRACE("bv", tout << mk_pp(e, m) << " " << mk_pp(translated(e), m) << "\n"); | ||||||
|         ctx.push(push_back_vector(m_preds)); |         ctx.push(push_back_vector(m_preds)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -476,6 +478,8 @@ namespace intblast { | ||||||
|                     continue; |                     continue; | ||||||
|                 if (sib->get_arg(0)->get_root() == r1) |                 if (sib->get_arg(0)->get_root() == r1) | ||||||
|                     continue; |                     continue; | ||||||
|  |                 if (bv.get_bv_size(r1->get_expr()) != bv.get_bv_size(sib->get_arg(0)->get_expr())) | ||||||
|  |                     continue; | ||||||
|                 auto a = eq_internalize(n, sib); |                 auto a = eq_internalize(n, sib); | ||||||
|                 auto b = eq_internalize(sib->get_arg(0), n->get_arg(0)); |                 auto b = eq_internalize(sib->get_arg(0), n->get_arg(0)); | ||||||
|                 ctx.mark_relevant(a); |                 ctx.mark_relevant(a); | ||||||
|  | @ -626,12 +630,12 @@ namespace intblast { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::translate_quantifier(quantifier* q) { |     void solver::translate_quantifier(quantifier* q) { | ||||||
|         if (is_lambda(q)) |  | ||||||
|             throw default_exception("lambdas are not supported in intblaster"); |  | ||||||
|         if (m_is_plugin) { |         if (m_is_plugin) { | ||||||
|             set_translated(q, q); |             set_translated(q, q); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |         if (is_lambda(q)) | ||||||
|  |             throw default_exception("lambdas are not supported in intblaster"); | ||||||
|         expr* b = q->get_expr(); |         expr* b = q->get_expr(); | ||||||
|         unsigned nd = q->get_num_decls(); |         unsigned nd = q->get_num_decls(); | ||||||
|         ptr_vector<sort> sorts; |         ptr_vector<sort> sorts; | ||||||
|  | @ -642,7 +646,6 @@ namespace intblast { | ||||||
|                 sorts.push_back(a.mk_int()); |                 sorts.push_back(a.mk_int()); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
| 
 |  | ||||||
|                 sorts.push_back(s); |                 sorts.push_back(s); | ||||||
|         } |         } | ||||||
|         b = translated(b); |         b = translated(b); | ||||||
|  | @ -767,6 +770,7 @@ namespace intblast { | ||||||
|             r = a.mk_le(smod(bv_expr, 0), smod(bv_expr, 1)); |             r = a.mk_le(smod(bv_expr, 0), smod(bv_expr, 1)); | ||||||
|             break; |             break; | ||||||
|         case OP_SGEQ: |         case OP_SGEQ: | ||||||
|  |             bv_expr = e->get_arg(0); | ||||||
|             r = a.mk_ge(smod(bv_expr, 0), smod(bv_expr, 1)); |             r = a.mk_ge(smod(bv_expr, 0), smod(bv_expr, 1)); | ||||||
|             break; |             break; | ||||||
|         case OP_SLT: |         case OP_SLT: | ||||||
|  | @ -815,13 +819,13 @@ namespace intblast { | ||||||
|         case OP_BUREM: |         case OP_BUREM: | ||||||
|         case OP_BUREM_I: { |         case OP_BUREM_I: { | ||||||
|             expr* x = umod(e, 0), * y = umod(e, 1); |             expr* x = umod(e, 0), * y = umod(e, 1); | ||||||
|             r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, a.mk_mod(x, y)); |             r = if_eq(y, 0, x, a.mk_mod(x, y)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case OP_BUDIV: |         case OP_BUDIV: | ||||||
|         case OP_BUDIV_I: { |         case OP_BUDIV_I: { | ||||||
|             expr* x = arg(0), * y = umod(e, 1); |             expr* x = umod(e, 0), * y = umod(e, 1); | ||||||
|             r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), a.mk_int(-1), a.mk_idiv(x, y)); |             r = if_eq(y, 0, a.mk_int(-1), a.mk_idiv(x, y)); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case OP_BUMUL_NO_OVFL: { |         case OP_BUMUL_NO_OVFL: { | ||||||
|  | @ -863,7 +867,7 @@ namespace intblast { | ||||||
|                 r = a.mk_int(0); |                 r = a.mk_int(0); | ||||||
|                 IF_VERBOSE(2, verbose_stream() << "shl " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); |                 IF_VERBOSE(2, verbose_stream() << "shl " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); | ||||||
|                 for (unsigned i = 0; i < bv.get_bv_size(e); ++i) |                 for (unsigned i = 0; i < bv.get_bv_size(e); ++i) | ||||||
|                     r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), mul(x, a.mk_int(rational::power_of_two(i))), r);    |                     r = if_eq(y, i, mul(x, a.mk_int(rational::power_of_two(i))), r);    | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | @ -878,7 +882,7 @@ namespace intblast { | ||||||
|                 r = a.mk_int(0); |                 r = a.mk_int(0); | ||||||
|                 IF_VERBOSE(2, verbose_stream() << "lshr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); |                 IF_VERBOSE(2, verbose_stream() << "lshr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); | ||||||
|                 for (unsigned i = 0; i < bv.get_bv_size(e); ++i) |                 for (unsigned i = 0; i < bv.get_bv_size(e); ++i) | ||||||
|                     r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_idiv(x, a.mk_int(rational::power_of_two(i))), r); |                     r = if_eq(y, i, a.mk_idiv(x, a.mk_int(rational::power_of_two(i))), r); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case OP_BASHR:  |         case OP_BASHR:  | ||||||
|  | @ -899,20 +903,19 @@ namespace intblast { | ||||||
|                 IF_VERBOSE(1, verbose_stream() << "ashr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); |                 IF_VERBOSE(1, verbose_stream() << "ashr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); | ||||||
|                 for (unsigned i = 0; i < sz; ++i) { |                 for (unsigned i = 0; i < sz; ++i) { | ||||||
|                     expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i)));               |                     expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i)));               | ||||||
|                     r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), |                     r = if_eq(y, i, | ||||||
|                                  m.mk_ite(signx, add(d, a.mk_int(- rational::power_of_two(sz-i))), d), |                                  m.mk_ite(signx, add(d, a.mk_int(- rational::power_of_two(sz-i))), d), | ||||||
|                                  r); |                                  r); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case OP_BOR: { |         case OP_BOR:  | ||||||
|             // p | q := (p + q) - band(p, q)
 |             // p | q := (p + q) - band(p, q)
 | ||||||
|             IF_VERBOSE(2, verbose_stream() << "bor " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); |             IF_VERBOSE(2, verbose_stream() << "bor " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); | ||||||
|             r = arg(0); |             r = arg(0); | ||||||
|             for (unsigned i = 1; i < args.size(); ++i) |             for (unsigned i = 1; i < args.size(); ++i) | ||||||
|                 r = a.mk_sub(add(r, arg(i)), a.mk_band(bv.get_bv_size(e), r, arg(i))); |                 r = a.mk_sub(add(r, arg(i)), a.mk_band(bv.get_bv_size(e), r, arg(i))); | ||||||
|             break;         |             break;         | ||||||
|         } |  | ||||||
|         case OP_BNAND: |         case OP_BNAND: | ||||||
|             r = bnot(band(args)); |             r = bnot(band(args)); | ||||||
|             break; |             break; | ||||||
|  | @ -982,8 +985,8 @@ namespace intblast { | ||||||
|             r = m.mk_ite(m.mk_and(m.mk_not(signx), signy), add(u, y), r); |             r = m.mk_ite(m.mk_and(m.mk_not(signx), signy), add(u, y), r); | ||||||
|             r = m.mk_ite(m.mk_and(signx, m.mk_not(signy)), a.mk_sub(y, u), r); |             r = m.mk_ite(m.mk_and(signx, m.mk_not(signy)), a.mk_sub(y, u), r); | ||||||
|             r = m.mk_ite(m.mk_and(m.mk_not(signx), m.mk_not(signy)), u, r); |             r = m.mk_ite(m.mk_and(m.mk_not(signx), m.mk_not(signy)), u, r); | ||||||
|             r = m.mk_ite(m.mk_eq(u, a.mk_int(0)), a.mk_int(0), r); |             r = if_eq(u, 0, a.mk_int(0), r); | ||||||
|             r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, r); |             r = if_eq(y, 0, x, r); | ||||||
|             break; |             break; | ||||||
|         }  |         }  | ||||||
|         case OP_BSDIV_I: |         case OP_BSDIV_I: | ||||||
|  | @ -1004,7 +1007,7 @@ namespace intblast { | ||||||
|             y = m.mk_ite(signy, a.mk_sub(a.mk_int(N), y), y); |             y = m.mk_ite(signy, a.mk_sub(a.mk_int(N), y), y); | ||||||
|             expr* d = a.mk_idiv(x, y); |             expr* d = a.mk_idiv(x, y); | ||||||
|             r = m.mk_ite(m.mk_iff(signx, signy), d, a.mk_uminus(d)); |             r = m.mk_ite(m.mk_iff(signx, signy), d, a.mk_uminus(d)); | ||||||
|             r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), m.mk_ite(signx, a.mk_int(1), a.mk_int(-1)), r); |             r = if_eq(y, 0, m.mk_ite(signx, a.mk_int(1), a.mk_int(-1)), r); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case OP_BSREM_I: |         case OP_BSREM_I: | ||||||
|  | @ -1020,7 +1023,7 @@ namespace intblast { | ||||||
|             expr* d = a.mk_idiv(absx, absy); |             expr* d = a.mk_idiv(absx, absy); | ||||||
|             d = m.mk_ite(m.mk_iff(signx, signy), d, a.mk_uminus(d)); |             d = m.mk_ite(m.mk_iff(signx, signy), d, a.mk_uminus(d)); | ||||||
|             r = a.mk_sub(x, mul(d, y)); |             r = a.mk_sub(x, mul(d, y)); | ||||||
|             r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, r); |             r = if_eq(y, 0, x, r); | ||||||
|             break;   |             break;   | ||||||
|         } |         } | ||||||
|         case OP_ROTATE_LEFT: { |         case OP_ROTATE_LEFT: { | ||||||
|  | @ -1039,7 +1042,7 @@ namespace intblast { | ||||||
|             expr* y = umod(e, 1); |             expr* y = umod(e, 1); | ||||||
|             r = a.mk_int(0); |             r = a.mk_int(0); | ||||||
|             for (unsigned i = 0; i < sz; ++i)  |             for (unsigned i = 0; i < sz; ++i)  | ||||||
|                 r = m.mk_ite(m.mk_eq(a.mk_int(i), y), rotate_left(i), r); |                 r = if_eq(y, i, rotate_left(i), r); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case OP_EXT_ROTATE_RIGHT: { |         case OP_EXT_ROTATE_RIGHT: { | ||||||
|  | @ -1047,7 +1050,7 @@ namespace intblast { | ||||||
|             expr* y = umod(e, 1); |             expr* y = umod(e, 1); | ||||||
|             r = a.mk_int(0); |             r = a.mk_int(0); | ||||||
|             for (unsigned i = 0; i < sz; ++i)  |             for (unsigned i = 0; i < sz; ++i)  | ||||||
|                 r = m.mk_ite(m.mk_eq(a.mk_int(i), y), rotate_left(sz - i), r); |                 r = if_eq(y, i, rotate_left(sz - i), r); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case OP_REPEAT: { |         case OP_REPEAT: { | ||||||
|  | @ -1078,6 +1081,18 @@ namespace intblast { | ||||||
|         set_translated(e, r); |         set_translated(e, r); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     expr_ref solver::if_eq(expr* n, unsigned k, expr* th, expr* el) { | ||||||
|  |         rational r; | ||||||
|  |         expr_ref _th(th, m), _el(el, m); | ||||||
|  |         if (bv.is_numeral(n, r)) { | ||||||
|  |             if (r == k) | ||||||
|  |                 return expr_ref(th, m); | ||||||
|  |             else | ||||||
|  |                 return expr_ref(el, m); | ||||||
|  |         } | ||||||
|  |         return expr_ref(m.mk_ite(m.mk_eq(n, a.mk_int(k)), th, el), m); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void solver::translate_basic(app* e) { |     void solver::translate_basic(app* e) { | ||||||
|         if (m.is_eq(e)) { |         if (m.is_eq(e)) { | ||||||
|             bool has_bv_arg = any_of(*e, [&](expr* arg) { return bv.is_bv(arg); }); |             bool has_bv_arg = any_of(*e, [&](expr* arg) { return bv.is_bv(arg); }); | ||||||
|  | @ -1136,7 +1151,7 @@ namespace intblast { | ||||||
|         if (e->get_family_id() != bv.get_family_id()) |         if (e->get_family_id() != bv.get_family_id()) | ||||||
|             return false; |             return false; | ||||||
|         for (euf::enode* arg : euf::enode_args(n)) |         for (euf::enode* arg : euf::enode_args(n)) | ||||||
|             dep.add(n, arg->get_root()); |             dep.add(n, arg); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1191,6 +1206,27 @@ namespace intblast { | ||||||
|         TRACE("model", tout << "add_value " << ctx.bpp(n) << " := " << value << "\n"); |         TRACE("model", tout << "add_value " << ctx.bpp(n) << " := " << value << "\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void solver::finalize_model(model& mdl) { | ||||||
|  |         return; | ||||||
|  |         for (auto n : ctx.get_egraph().nodes()) { | ||||||
|  |             auto e = n->get_expr();             | ||||||
|  |             if (!is_translated(e)) | ||||||
|  |                 continue; | ||||||
|  |             if (!bv.is_bv(e)) | ||||||
|  |                 continue; | ||||||
|  |             auto t = translated(e); | ||||||
|  |              | ||||||
|  |             expr_ref ei(bv.mk_bv2int(e), m); | ||||||
|  |             expr_ref ti(a.mk_mod(t, a.mk_int(rational::power_of_two(bv.get_bv_size(e)))), m); | ||||||
|  |             auto ev = mdl(ei); | ||||||
|  |             auto tv = mdl(ti); | ||||||
|  |             if (ev != tv) { | ||||||
|  |                 IF_VERBOSE(0, verbose_stream() << mk_pp(e, m) << " <- " << ev << "\n"); | ||||||
|  |                 IF_VERBOSE(0, verbose_stream() << mk_pp(t, m) << " <- " << tv << "\n"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     sat::literal_vector const& solver::unsat_core() { |     sat::literal_vector const& solver::unsat_core() { | ||||||
|         return m_core; |         return m_core; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -77,6 +77,7 @@ namespace intblast { | ||||||
|         bool is_non_negative(expr* bv_expr, expr* e); |         bool is_non_negative(expr* bv_expr, expr* e); | ||||||
|         expr_ref mul(expr* x, expr* y); |         expr_ref mul(expr* x, expr* y); | ||||||
|         expr_ref add(expr* x, expr* y); |         expr_ref add(expr* x, expr* y); | ||||||
|  |         expr_ref if_eq(expr* n, unsigned k, expr* th, expr* el); | ||||||
|         expr* amod(expr* bv_expr, expr* x, rational const& N); |         expr* amod(expr* bv_expr, expr* x, rational const& N); | ||||||
|         rational bv_size(expr* bv_expr); |         rational bv_size(expr* bv_expr); | ||||||
| 
 | 
 | ||||||
|  | @ -147,6 +148,7 @@ namespace intblast { | ||||||
| 
 | 
 | ||||||
|         rational get_value(expr* e) const; |         rational get_value(expr* e) const; | ||||||
| 
 | 
 | ||||||
|  |         void finalize_model(model& mdl) override; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -148,6 +148,8 @@ namespace euf { | ||||||
| 
 | 
 | ||||||
|         virtual void set_bounds(enode* n) {} |         virtual void set_bounds(enode* n) {} | ||||||
| 
 | 
 | ||||||
|  |         virtual void finalize() {} | ||||||
|  | 
 | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     class th_proof_hint : public sat::proof_hint { |     class th_proof_hint : public sat::proof_hint { | ||||||
|  | @ -223,6 +225,7 @@ namespace euf { | ||||||
|         void push() override { m_num_scopes++; } |         void push() override { m_num_scopes++; } | ||||||
|         void pop(unsigned n) override; |         void pop(unsigned n) override; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         unsigned random(); |         unsigned random(); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,109 +22,145 @@ Author: | ||||||
| 
 | 
 | ||||||
| namespace sls { | namespace sls { | ||||||
| 
 | 
 | ||||||
|  | #ifdef SINGLE_THREAD | ||||||
|  | 
 | ||||||
|  |     solver::solver(euf::solver& ctx) : | ||||||
|  |         th_euf_solver(ctx, symbol("sls"), ctx.get_manager().mk_family_id("sls")) | ||||||
|  |         {} | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|     solver::solver(euf::solver& ctx): |     solver::solver(euf::solver& ctx): | ||||||
|         th_euf_solver(ctx, symbol("sls"), ctx.get_manager().mk_family_id("sls")) {} |         th_euf_solver(ctx, symbol("sls"), ctx.get_manager().mk_family_id("sls")) | ||||||
|  |         {} | ||||||
| 
 | 
 | ||||||
|     solver::~solver() { |     solver::~solver() { | ||||||
|         if (m_bvsls) { |         finalize(); | ||||||
|             m_bvsls->cancel();             |     } | ||||||
|  | 
 | ||||||
|  |     void solver::finalize() { | ||||||
|  |         if (!m_completed && m_sls) { | ||||||
|  |             m_sls->cancel(); | ||||||
|             m_thread.join(); |             m_thread.join(); | ||||||
|  |             m_sls->collect_statistics(m_st); | ||||||
|  |             m_sls = nullptr; | ||||||
|  |             m_shared = nullptr; | ||||||
|  |             m_slsm = nullptr; | ||||||
|  |             m_units = nullptr; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::push_core() { |     sat::check_result solver::check() {  | ||||||
|         if (s().scope_lvl() == s().search_lvl() + 1) |         return sat::check_result::CR_DONE;  | ||||||
|             init_local_search(); |     } | ||||||
|  | 
 | ||||||
|  |     bool solver::unit_propagate() { | ||||||
|  |         force_push(); | ||||||
|  |         sample_local_search(); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool solver::is_unit(expr* e) { | ||||||
|  |         if (!e) | ||||||
|  |             return false; | ||||||
|  |         m.is_not(e, e); | ||||||
|  |         if (is_uninterp_const(e)) | ||||||
|  |             return true; | ||||||
|  |         bv_util bu(m); | ||||||
|  |         expr* s; | ||||||
|  |         if (bu.is_bit2bool(e, s)) | ||||||
|  |             return is_uninterp_const(s); | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::pop_core(unsigned n) { |     void solver::pop_core(unsigned n) { | ||||||
|         if (s().scope_lvl() - n <= s().search_lvl()) |         for (; m_trail_lim < s().init_trail_size(); ++m_trail_lim) { | ||||||
|             sample_local_search(); |             auto lit = s().trail_literal(m_trail_lim); | ||||||
|     } |             auto e = ctx.literal2expr(lit); | ||||||
| 
 |             if (is_unit(e)) { | ||||||
|     void solver::simplify() { |                 // IF_VERBOSE(1, verbose_stream() << "add unit " << mk_pp(e, m) << "\n");
 | ||||||
|      |                 std::lock_guard<std::mutex> lock(m_mutex); | ||||||
|     } |                 ast_translation tr(m, *m_shared); | ||||||
|          |                 m_units->push_back(tr(e.get())); | ||||||
| 
 |                 m_has_units = true; | ||||||
|     void solver::init_local_search() { |  | ||||||
|         if (m_bvsls) { |  | ||||||
|             m_bvsls->cancel(); |  | ||||||
|             m_thread.join(); |  | ||||||
|             if (m_result == l_true) { |  | ||||||
|                 verbose_stream() << "Found model using local search - INIT\n"; |  | ||||||
|                 exit(1); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     }        | ||||||
|  | 
 | ||||||
|  |     void solver::init_search() { | ||||||
|  |         if (m_sls) { | ||||||
|  |             m_sls->cancel(); | ||||||
|  |             m_thread.join(); | ||||||
|  |             m_result = l_undef; | ||||||
|  |             m_completed = false; | ||||||
|  |             m_has_units = false; | ||||||
|  |             m_model = nullptr; | ||||||
|  |             m_units = nullptr; | ||||||
|  |         } | ||||||
|         // set up state for local search solver here
 |         // set up state for local search solver here
 | ||||||
| 
 | 
 | ||||||
|         m_m = alloc(ast_manager, m); |         m_shared = alloc(ast_manager); | ||||||
|         ast_translation tr(m, *m_m); |         m_slsm = alloc(ast_manager); | ||||||
|  |         m_units = alloc(expr_ref_vector, *m_shared); | ||||||
|  |         ast_translation tr(m, *m_slsm); | ||||||
|          |          | ||||||
|         m_completed = false; |         m_completed = false; | ||||||
|         m_result = l_undef; |         m_result = l_undef; | ||||||
|         m_bvsls = alloc(bv::sls, *m_m); |         m_model = nullptr; | ||||||
|         // walk clauses, add them
 |         m_sls = alloc(bv::sls, *m_slsm, s().params()); | ||||||
|         // walk trail stack until search level, add units
 |  | ||||||
|         // encapsulate bvsls within the arguments of run-local-search.
 |  | ||||||
|         // ensure bvsls does not touch ast-manager.
 |  | ||||||
|          |          | ||||||
|         unsigned trail_sz = s().trail_size(); |         for (expr* a : ctx.get_assertions()) | ||||||
|         for (unsigned i = 0; i < trail_sz; ++i) { |             m_sls->assert_expr(tr(a)); | ||||||
|             auto lit = s().trail_literal(i); |  | ||||||
|             if (s().lvl(lit) > s().search_lvl()) |  | ||||||
|                 break; |  | ||||||
|             expr_ref fml = literal2expr(lit); |  | ||||||
|             m_bvsls->assert_expr(tr(fml.get())); |  | ||||||
|         } |  | ||||||
|         unsigned num_vars = s().num_vars(); |  | ||||||
|         for (unsigned i = 0; i < 2*num_vars; ++i) { |  | ||||||
|             auto l1 = ~sat::to_literal(i); |  | ||||||
|             auto const& wlist = s().get_wlist(l1); |  | ||||||
|             for (sat::watched const& w : wlist) { |  | ||||||
|                 if (!w.is_binary_non_learned_clause()) |  | ||||||
|                     continue; |  | ||||||
|                 sat::literal l2 = w.get_literal(); |  | ||||||
|                 if (l1.index() > l2.index()) |  | ||||||
|                     continue; |  | ||||||
|                 expr_ref fml(m.mk_or(literal2expr(l1), literal2expr(l2)), m); |  | ||||||
|                 m_bvsls->assert_expr(tr(fml.get())); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         for (auto clause : s().clauses()) { |  | ||||||
|             expr_ref_vector cls(m); |  | ||||||
|             for (auto lit : *clause) |  | ||||||
|                 cls.push_back(literal2expr(lit)); |  | ||||||
|             expr_ref fml(m.mk_or(cls), m); |  | ||||||
|             m_bvsls->assert_expr(tr(fml.get())); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // use phase assignment from literals?
 |  | ||||||
|         std::function<bool(expr*, unsigned)> eval = [&](expr* e, unsigned r) { |         std::function<bool(expr*, unsigned)> eval = [&](expr* e, unsigned r) { | ||||||
|             return false; |             return false; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         m_bvsls->init(); |         m_sls->init(); | ||||||
|         m_bvsls->init_eval(eval); |         m_sls->init_eval(eval); | ||||||
|         m_bvsls->updt_params(s().params()); |         m_sls->updt_params(s().params()); | ||||||
|  |         m_sls->init_unit([&]() {  | ||||||
|  |             if (!m_has_units) | ||||||
|  |                 return expr_ref(*m_slsm); | ||||||
|  |             expr_ref e(*m_slsm); | ||||||
|  |             { | ||||||
|  |                 std::lock_guard<std::mutex> lock(m_mutex); | ||||||
|  |                 if (m_units->empty()) | ||||||
|  |                     return expr_ref(*m_slsm); | ||||||
|  |                 ast_translation tr(*m_shared, *m_slsm); | ||||||
|  |                 e = tr(m_units->back()); | ||||||
|  |                 m_units->pop_back(); | ||||||
|  |             } | ||||||
|  |             return e; | ||||||
|  |         }); | ||||||
|  |         m_sls->set_model([&](model& mdl) { | ||||||
|  |             std::lock_guard<std::mutex> lock(m_mutex); | ||||||
|  |             ast_translation tr(*m_shared, m); | ||||||
|  |             m_model = mdl.translate(tr); | ||||||
|  |         }); | ||||||
|                                       |                                       | ||||||
|         m_thread = std::thread([this]() { run_local_search(); });         |         m_thread = std::thread([this]() { run_local_search(); });         | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::sample_local_search() { |     void solver::sample_local_search() { | ||||||
|         if (m_completed) { |         if (!m_completed) | ||||||
|             m_thread.join(); |             return;         | ||||||
|             if (m_result == l_true) { |         m_thread.join(); | ||||||
|                 verbose_stream() << "Found model using local search\n"; |         m_completed = false; | ||||||
|                 exit(1); |         m_sls->collect_statistics(m_st); | ||||||
|             } |         if (m_result == l_true) { | ||||||
|  |             IF_VERBOSE(2, verbose_stream() << "(sat.sls :model-completed)\n";); | ||||||
|  |             auto mdl = m_sls->get_model(); | ||||||
|  |             ast_translation tr(*m_slsm, m); | ||||||
|  |             m_model = mdl->translate(tr); | ||||||
|  |             s().set_canceled(); | ||||||
|         } |         } | ||||||
|  |         m_sls = nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::run_local_search() { |     void solver::run_local_search() { | ||||||
|         lbool r = (*m_bvsls)(); |         m_result = (*m_sls)(); | ||||||
|         m_result = r; |  | ||||||
|         m_completed = true; |         m_completed = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,12 +16,15 @@ Author: | ||||||
| --*/ | --*/ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <thread> | 
 | ||||||
| #include "util/rlimit.h" | #include "util/rlimit.h" | ||||||
| #include "ast/sls/bv_sls.h" | #include "ast/sls/bv_sls.h" | ||||||
| #include "sat/smt/sat_th.h" | #include "sat/smt/sat_th.h" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #ifdef SINGLE_THREAD | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| namespace euf { | namespace euf { | ||||||
|     class solver; |     class solver; | ||||||
| } | } | ||||||
|  | @ -29,31 +32,72 @@ namespace euf { | ||||||
| namespace sls { | namespace sls { | ||||||
| 
 | 
 | ||||||
|     class solver : public euf::th_euf_solver { |     class solver : public euf::th_euf_solver { | ||||||
|         std::atomic<lbool> m_result; |  | ||||||
|         std::atomic<bool> m_completed; |  | ||||||
|         std::thread m_thread; |  | ||||||
|         scoped_ptr<ast_manager> m_m; |  | ||||||
|         scoped_ptr<bv::sls> m_bvsls; |  | ||||||
| 
 |  | ||||||
|         void run_local_search(); |  | ||||||
|         void init_local_search(); |  | ||||||
|         void sample_local_search(); |  | ||||||
|     public: |     public: | ||||||
|         solver(euf::solver& ctx); |         solver(euf::solver& ctx); | ||||||
|         ~solver(); |  | ||||||
| 
 |  | ||||||
|         void push_core() override; |  | ||||||
|         void pop_core(unsigned n) override; |  | ||||||
|         void simplify() override; |  | ||||||
|              |              | ||||||
|         sat::literal internalize(expr* e, bool sign, bool root) override { UNREACHABLE();  return sat::null_literal; } |         sat::literal internalize(expr* e, bool sign, bool root) override { UNREACHABLE();  return sat::null_literal; } | ||||||
|         void internalize(expr* e) override { UNREACHABLE(); } |         void internalize(expr* e) override { UNREACHABLE(); } | ||||||
|         th_solver* clone(euf::solver& ctx) override { return alloc(solver, ctx); } |         th_solver* clone(euf::solver& ctx) override { return alloc(solver, ctx); } | ||||||
| 
 | 
 | ||||||
| 
 |         model_ref get_model() { return model_ref(nullptr); } | ||||||
|         bool unit_propagate() override { return false; } |         bool unit_propagate() override { return false; } | ||||||
|  |         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;} | ||||||
|  |         std::ostream& display(std::ostream& out) const override { return out; } | ||||||
|  |         std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override { UNREACHABLE(); return out; } | ||||||
|  |         std::ostream& display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const override { UNREACHABLE(); return out; } | ||||||
|  | 
 | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 
 | ||||||
|  | #include <thread> | ||||||
|  | #include <mutex> | ||||||
|  | 
 | ||||||
|  | namespace euf { | ||||||
|  |     class solver; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace sls { | ||||||
|  | 
 | ||||||
|  |     class solver : public euf::th_euf_solver { | ||||||
|  |         std::atomic<lbool> m_result; | ||||||
|  |         std::atomic<bool> m_completed, m_has_units; | ||||||
|  |         std::thread m_thread; | ||||||
|  |         std::mutex  m_mutex; | ||||||
|  |         // m is accessed by the main thread
 | ||||||
|  |         // m_slsm is accessed by the sls thread
 | ||||||
|  |         // m_shared is only accessed at synchronization points
 | ||||||
|  |         scoped_ptr<ast_manager> m_shared, m_slsm; | ||||||
|  |         scoped_ptr<bv::sls> m_sls; | ||||||
|  |         scoped_ptr<expr_ref_vector> m_units; | ||||||
|  |         model_ref m_model; | ||||||
|  |         unsigned m_trail_lim = 0; | ||||||
|  |         statistics m_st; | ||||||
|  | 
 | ||||||
|  |         void run_local_search(); | ||||||
|  |         void sample_local_search(); | ||||||
|  |         bool is_unit(expr*); | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         solver(euf::solver& ctx); | ||||||
|  |         ~solver(); | ||||||
|  | 
 | ||||||
|  |         model_ref get_model() { return m_model; } | ||||||
|  | 
 | ||||||
|  |         void init_search() override; | ||||||
|  |         void push_core() override {} | ||||||
|  |         void pop_core(unsigned n) override; | ||||||
|  |         th_solver* clone(euf::solver& ctx) override { return alloc(solver, ctx); } | ||||||
|  |         void collect_statistics(statistics& st) const override { st.copy(m_st); }        | ||||||
|  |         void finalize() override; | ||||||
|  |         bool unit_propagate() override; | ||||||
|  | 
 | ||||||
|  |         sat::literal internalize(expr* e, bool sign, bool root) override { UNREACHABLE();  return sat::null_literal; } | ||||||
|  |         void internalize(expr* e) override { UNREACHABLE(); } | ||||||
|         void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override { UNREACHABLE(); } |         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; } |         sat::check_result check() override; | ||||||
|         std::ostream & display(std::ostream & out) const override { return out; } |         std::ostream & display(std::ostream & out) const override { return out; } | ||||||
|         std::ostream & display_justification(std::ostream & out, sat::ext_justification_idx idx) const override { UNREACHABLE(); return out; } |         std::ostream & display_justification(std::ostream & out, sat::ext_justification_idx idx) const override { UNREACHABLE(); return out; } | ||||||
|         std::ostream & display_constraint(std::ostream & out, sat::ext_constraint_idx idx) const override { UNREACHABLE(); return out; } |         std::ostream & display_constraint(std::ostream & out, sat::ext_constraint_idx idx) const override { UNREACHABLE(); return out; } | ||||||
|  | @ -61,3 +105,5 @@ namespace sls { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -895,6 +895,7 @@ struct goal2sat::imp : public sat::sat_internalizer { | ||||||
|         process(n, true); |         process(n, true); | ||||||
|         CTRACE("goal2sat", !m_result_stack.empty(), tout << m_result_stack << "\n";); |         CTRACE("goal2sat", !m_result_stack.empty(), tout << m_result_stack << "\n";); | ||||||
|         SASSERT(m_result_stack.empty()); |         SASSERT(m_result_stack.empty()); | ||||||
|  |         add_assertion(n); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void insert_dep(expr* dep0, expr* dep, bool sign) { |     void insert_dep(expr* dep0, expr* dep, bool sign) { | ||||||
|  | @ -989,6 +990,12 @@ struct goal2sat::imp : public sat::sat_internalizer { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void add_assertion(expr* f) { | ||||||
|  |         auto* ext = dynamic_cast<euf::solver*>(m_solver.get_extension()); | ||||||
|  |         if (ext) | ||||||
|  |             ext->add_assertion(f); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void update_model(model_ref& mdl) { |     void update_model(model_ref& mdl) { | ||||||
|         auto* ext = dynamic_cast<euf::solver*>(m_solver.get_extension()); |         auto* ext = dynamic_cast<euf::solver*>(m_solver.get_extension()); | ||||||
|         if (ext) |         if (ext) | ||||||
|  |  | ||||||
|  | @ -49,6 +49,7 @@ void smt_params::updt_local_params(params_ref const & _p) { | ||||||
|     m_threads_max_conflicts  = p.threads_max_conflicts(); |     m_threads_max_conflicts  = p.threads_max_conflicts(); | ||||||
|     m_threads_cube_frequency = p.threads_cube_frequency(); |     m_threads_cube_frequency = p.threads_cube_frequency(); | ||||||
|     m_core_validate = p.core_validate(); |     m_core_validate = p.core_validate(); | ||||||
|  |     m_sls_enable = p.sls_enable(); | ||||||
|     m_logic = _p.get_sym("logic", m_logic); |     m_logic = _p.get_sym("logic", m_logic); | ||||||
|     m_string_solver = p.string_solver(); |     m_string_solver = p.string_solver(); | ||||||
|     m_up_persist_clauses = p.up_persist_clauses(); |     m_up_persist_clauses = p.up_persist_clauses(); | ||||||
|  | @ -66,6 +67,7 @@ void smt_params::updt_local_params(params_ref const & _p) { | ||||||
|     m_lemmas2console = sp.lemmas2console(); |     m_lemmas2console = sp.lemmas2console(); | ||||||
|     m_instantiations2console = sp.instantiations2console(); |     m_instantiations2console = sp.instantiations2console(); | ||||||
|     m_proof_log = sp.proof_log(); |     m_proof_log = sp.proof_log(); | ||||||
|  |      | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void smt_params::updt_params(params_ref const & p) { | void smt_params::updt_params(params_ref const & p) { | ||||||
|  |  | ||||||
|  | @ -114,6 +114,7 @@ struct smt_params : public preprocessor_params, | ||||||
|     bool             m_induction = false; |     bool             m_induction = false; | ||||||
|     bool             m_clause_proof = false; |     bool             m_clause_proof = false; | ||||||
|     symbol           m_proof_log; |     symbol           m_proof_log; | ||||||
|  |     bool             m_sls_enable = false; | ||||||
| 
 | 
 | ||||||
|     // -----------------------------------
 |     // -----------------------------------
 | ||||||
|     //
 |     //
 | ||||||
|  |  | ||||||
|  | @ -83,6 +83,7 @@ def_module_params(module_name='smt', | ||||||
| 			  ('arith.nl.propagate_linear_monomials', BOOL, True, 'propagate linear monomials'), | 			  ('arith.nl.propagate_linear_monomials', BOOL, True, 'propagate linear monomials'), | ||||||
| 			  ('arith.nl.optimize_bounds', BOOL, True, 'enable bounds optimization'), | 			  ('arith.nl.optimize_bounds', BOOL, True, 'enable bounds optimization'), | ||||||
| 			  ('arith.nl.cross_nested', BOOL, True, 'enable cross-nested consistency checking'), | 			  ('arith.nl.cross_nested', BOOL, True, 'enable cross-nested consistency checking'), | ||||||
|  | 			  ('arith.nl.log', BOOL, False, 'Log lemmas sent to nra solver'), | ||||||
|                           ('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'), |                           ('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'), | ||||||
|                           ('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'), |                           ('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'), | ||||||
|                           ('arith.branch_cut_ratio', UINT, 2, 'branch/cut ratio for linear integer arithmetic'), |                           ('arith.branch_cut_ratio', UINT, 2, 'branch/cut ratio for linear integer arithmetic'), | ||||||
|  | @ -135,6 +136,7 @@ def_module_params(module_name='smt', | ||||||
|                           ('str.regex_automata_length_attempt_threshold', UINT, 10, 'number of length/path constraint attempts before checking unsatisfiability of regex terms'), |                           ('str.regex_automata_length_attempt_threshold', UINT, 10, 'number of length/path constraint attempts before checking unsatisfiability of regex terms'), | ||||||
|                           ('str.fixed_length_refinement', BOOL, False, 'use abstraction refinement in fixed-length equation solver (Z3str3 only)'), |                           ('str.fixed_length_refinement', BOOL, False, 'use abstraction refinement in fixed-length equation solver (Z3str3 only)'), | ||||||
|                           ('str.fixed_length_naive_cex', BOOL, True, 'construct naive counterexamples when fixed-length model construction fails for a given length assignment (Z3str3 only)'), |                           ('str.fixed_length_naive_cex', BOOL, True, 'construct naive counterexamples when fixed-length model construction fails for a given length assignment (Z3str3 only)'), | ||||||
|  |                           ('sls.enable', BOOL, False, 'enable sls co-processor with SMT engine'), | ||||||
|                           ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), |                           ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), | ||||||
|                           ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), |                           ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), | ||||||
|                           ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), |                           ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), | ||||||
|  |  | ||||||
|  | @ -49,8 +49,18 @@ Notes: | ||||||
| #include "parsers/smt2/smt2parser.h" | #include "parsers/smt2/smt2parser.h" | ||||||
| #include "sat/sat_params.hpp" | #include "sat/sat_params.hpp" | ||||||
| 
 | 
 | ||||||
|  | tactic* mk_tactic_for_logic(ast_manager& m, params_ref const& p, symbol const& logic); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class smt_nested_solver_factory : public solver_factory { | ||||||
|  | public: | ||||||
|  |     solver* operator()(ast_manager& m, params_ref const& p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const& logic) override { | ||||||
|  |         auto t = mk_tactic_for_logic(m, p, logic); | ||||||
|  |         auto s = mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, logic); | ||||||
|  |         return s; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) { | tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) { | ||||||
|     if (logic=="QF_UF") |     if (logic=="QF_UF") | ||||||
|         return mk_qfuf_tactic(m, p); |         return mk_qfuf_tactic(m, p); | ||||||
|  |  | ||||||
|  | @ -134,7 +134,7 @@ public: | ||||||
|     bv_sls_tactic(ast_manager& _m, params_ref const& p) : |     bv_sls_tactic(ast_manager& _m, params_ref const& p) : | ||||||
|         m(_m), |         m(_m), | ||||||
|         m_params(p) { |         m_params(p) { | ||||||
|         m_sls = alloc(bv::sls, m); |         m_sls = alloc(bv::sls, m, p); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     tactic* translate(ast_manager& m) override { |     tactic* translate(ast_manager& m) override { | ||||||
|  | @ -172,12 +172,12 @@ public: | ||||||
|         m_sls->init_eval(false_eval); |         m_sls->init_eval(false_eval); | ||||||
| 
 | 
 | ||||||
|         lbool res = m_sls->operator()(); |         lbool res = m_sls->operator()(); | ||||||
|         auto const& stats = m_sls->get_stats(); |  | ||||||
|         report_tactic_progress("Number of flips:", stats.m_moves); |  | ||||||
|         IF_VERBOSE(20, verbose_stream() << res << "\n"); |  | ||||||
|         IF_VERBOSE(20, m_sls->display(verbose_stream())); |  | ||||||
|         m_st.reset(); |         m_st.reset(); | ||||||
|         m_sls->collect_statistics(m_st); |         m_sls->collect_statistics(m_st); | ||||||
|  |         report_tactic_progress("Number of flips:", m_sls->get_num_moves()); | ||||||
|  |         IF_VERBOSE(10, verbose_stream() << res << "\n"); | ||||||
|  |         IF_VERBOSE(10, m_sls->display(verbose_stream())); | ||||||
|  | 
 | ||||||
|         if (res == l_true) {             |         if (res == l_true) {             | ||||||
|             if (g->models_enabled()) { |             if (g->models_enabled()) { | ||||||
|                 model_ref mdl = m_sls->get_model(); |                 model_ref mdl = m_sls->get_model(); | ||||||
|  | @ -207,7 +207,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     void cleanup() override { |     void cleanup() override { | ||||||
| 
 | 
 | ||||||
|         auto* d = alloc(bv::sls, m); |         auto* d = alloc(bv::sls, m, m_params); | ||||||
|         std::swap(d, m_sls); |         std::swap(d, m_sls); | ||||||
|         dealloc(d); |         dealloc(d); | ||||||
|     } |     } | ||||||
|  | @ -235,12 +235,6 @@ tactic* mk_bv_sls_tactic(ast_manager& m, params_ref const& p) { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static tactic * mk_preamble(ast_manager & m, params_ref const & p) { | static tactic * mk_preamble(ast_manager & m, params_ref const & p) { | ||||||
|     params_ref main_p; |  | ||||||
|     main_p.set_bool("elim_and", true); |  | ||||||
|     // main_p.set_bool("pull_cheap_ite", true);
 |  | ||||||
|     main_p.set_bool("push_ite_bv", true); |  | ||||||
|     main_p.set_bool("blast_distinct", true); |  | ||||||
|     main_p.set_bool("hi_div0", true); |  | ||||||
| 
 | 
 | ||||||
|     params_ref simp2_p = p; |     params_ref simp2_p = p; | ||||||
|     simp2_p.set_bool("som", true); |     simp2_p.set_bool("som", true); | ||||||
|  | @ -249,18 +243,15 @@ static tactic * mk_preamble(ast_manager & m, params_ref const & p) { | ||||||
|     simp2_p.set_bool("local_ctx", true); |     simp2_p.set_bool("local_ctx", true); | ||||||
|     simp2_p.set_uint("local_ctx_limit", 10000000); |     simp2_p.set_uint("local_ctx_limit", 10000000); | ||||||
| 
 | 
 | ||||||
|     params_ref hoist_p; |     params_ref hoist_p = p; | ||||||
|     hoist_p.set_bool("hoist_mul", true); |     hoist_p.set_bool("hoist_mul", true); | ||||||
|     hoist_p.set_bool("som", false); |     hoist_p.set_bool("som", false); | ||||||
| 
 | 
 | ||||||
|     params_ref gaussian_p; |     params_ref gaussian_p = p; | ||||||
|     // conservative gaussian elimination. 
 |     // conservative gaussian elimination. 
 | ||||||
|     gaussian_p.set_uint("gaussian_max_occs", 2);  |     gaussian_p.set_uint("gaussian_max_occs", 2);  | ||||||
| 
 | 
 | ||||||
|     params_ref ctx_p; |     return and_then(and_then(mk_simplify_tactic(m, p),                              | ||||||
|     ctx_p.set_uint("max_depth", 32); |  | ||||||
|     ctx_p.set_uint("max_steps", 5000000); |  | ||||||
|     return and_then(and_then(mk_simplify_tactic(m),                              |  | ||||||
|                              mk_propagate_values_tactic(m), |                              mk_propagate_values_tactic(m), | ||||||
|                              using_params(mk_solve_eqs_tactic(m), gaussian_p), |                              using_params(mk_solve_eqs_tactic(m), gaussian_p), | ||||||
|                              mk_elim_uncnstr_tactic(m), |                              mk_elim_uncnstr_tactic(m), | ||||||
|  | @ -278,7 +269,9 @@ tactic * mk_qfbv_sls_tactic(ast_manager & m, params_ref const & p) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| tactic* mk_qfbv_new_sls_tactic(ast_manager& m, params_ref const& p) { | tactic* mk_qfbv_new_sls_tactic(ast_manager& m, params_ref const& p) { | ||||||
|     tactic* t = and_then(mk_preamble(m, p), mk_bv_sls_tactic(m, p)); |     params_ref q = p; | ||||||
|     t->updt_params(p); |     q.set_bool("elim_sign_ext", false); | ||||||
|  |     tactic* t = and_then(mk_preamble(m, q), mk_bv_sls_tactic(m, q)); | ||||||
|  |     t->updt_params(q); | ||||||
|     return t; |     return t; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ Revision History: | ||||||
| --*/ | --*/ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <type_traits> | #include <cstddef> | ||||||
| #include "util/memory_manager.h" | #include "util/memory_manager.h" | ||||||
| 
 | 
 | ||||||
| template<typename T, bool CallDestructors=true, unsigned INITIAL_SIZE=16> | template<typename T, bool CallDestructors=true, unsigned INITIAL_SIZE=16> | ||||||
|  | @ -30,8 +30,7 @@ protected: | ||||||
|     T *      m_buffer = reinterpret_cast<T*>(m_initial_buffer); |     T *      m_buffer = reinterpret_cast<T*>(m_initial_buffer); | ||||||
|     unsigned m_pos = 0; |     unsigned m_pos = 0; | ||||||
|     unsigned m_capacity = INITIAL_SIZE; |     unsigned m_capacity = INITIAL_SIZE; | ||||||
|     alignas(T) std::byte m_initial_buffer[sizeof(T)*INITIAL_SIZE]; |     alignas(T) std::byte m_initial_buffer[INITIAL_SIZE * sizeof(T)]; | ||||||
| //    typename std::aligned_storage<sizeof(T), alignof(T)>::type m_initial_buffer[INITIAL_SIZE];
 |  | ||||||
| 
 | 
 | ||||||
|     void free_memory() { |     void free_memory() { | ||||||
|         if (m_buffer != reinterpret_cast<T*>(m_initial_buffer)) { |         if (m_buffer != reinterpret_cast<T*>(m_initial_buffer)) { | ||||||
|  |  | ||||||
|  | @ -75,6 +75,37 @@ bool is_debug_enabled(const char * tag) { | ||||||
|     return g_enabled_debug_tags->contains(tag); |     return g_enabled_debug_tags->contains(tag); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | atomic<exit_action> g_default_exit_action(exit_action::exit); | ||||||
|  | 
 | ||||||
|  | exit_action get_default_exit_action() { | ||||||
|  |     return g_default_exit_action; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void set_default_exit_action(exit_action a) { | ||||||
|  |     g_default_exit_action = a; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void invoke_exit_action(unsigned int code) { | ||||||
|  |     exit_action a = get_default_exit_action(); | ||||||
|  |     switch (a) { | ||||||
|  |     case exit_action::exit: | ||||||
|  |         exit(code); | ||||||
|  |     case exit_action::throw_exception: | ||||||
|  |         switch (code) { | ||||||
|  |             case ERR_INTERNAL_FATAL: | ||||||
|  |                 throw default_exception("internal fatal"); | ||||||
|  |             case ERR_UNREACHABLE: | ||||||
|  |                 throw default_exception("unreachable"); | ||||||
|  |             case ERR_NOT_IMPLEMENTED_YET: | ||||||
|  |                 throw default_exception("not implemented yet"); | ||||||
|  |             default: | ||||||
|  |                 throw default_exception("unknown"); | ||||||
|  |         } | ||||||
|  |     default: | ||||||
|  |         exit(code); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| atomic<debug_action> g_default_debug_action(debug_action::ask); | atomic<debug_action> g_default_debug_action(debug_action::ask); | ||||||
| 
 | 
 | ||||||
| debug_action get_default_debug_action() { | debug_action get_default_debug_action() { | ||||||
|  |  | ||||||
|  | @ -35,6 +35,14 @@ enum class debug_action { | ||||||
| debug_action get_default_debug_action(); | debug_action get_default_debug_action(); | ||||||
| void set_default_debug_action(debug_action a); | void set_default_debug_action(debug_action a); | ||||||
| 
 | 
 | ||||||
|  | enum class exit_action { | ||||||
|  |     exit, | ||||||
|  |     throw_exception, | ||||||
|  | }; | ||||||
|  | exit_action get_default_exit_action(); | ||||||
|  | void set_default_exit_action(exit_action a); | ||||||
|  | void invoke_exit_action(unsigned int code); | ||||||
|  | 
 | ||||||
| #include "util/error_codes.h" | #include "util/error_codes.h" | ||||||
| #include "util/warning.h" | #include "util/warning.h" | ||||||
| 
 | 
 | ||||||
|  | @ -56,7 +64,7 @@ void set_default_debug_action(debug_action a); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef NO_Z3_DEBUGGER | #ifdef NO_Z3_DEBUGGER | ||||||
| #define INVOKE_DEBUGGER() exit(ERR_INTERNAL_FATAL) | #define INVOKE_DEBUGGER() invoke_exit_action(ERR_INTERNAL_FATAL) | ||||||
| #else | #else | ||||||
| #ifdef _WINDOWS | #ifdef _WINDOWS | ||||||
| #define INVOKE_DEBUGGER() __debugbreak() | #define INVOKE_DEBUGGER() __debugbreak() | ||||||
|  | @ -71,6 +79,7 @@ void enable_debug(const char * tag); | ||||||
| void disable_debug(const char * tag); | void disable_debug(const char * tag); | ||||||
| bool is_debug_enabled(const char * tag); | bool is_debug_enabled(const char * tag); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| #define SASSERT(COND) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) | #define SASSERT(COND) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) | ||||||
| #define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) | #define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) | ||||||
| #define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); }) | #define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); }) | ||||||
|  | @ -85,26 +94,25 @@ bool is_debug_enabled(const char * tag); | ||||||
| #ifdef Z3DEBUG | #ifdef Z3DEBUG | ||||||
| # define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNEXPECTED CODE WAS REACHED."); INVOKE_DEBUGGER();) | # define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNEXPECTED CODE WAS REACHED."); INVOKE_DEBUGGER();) | ||||||
| #else | #else | ||||||
| # define UNREACHABLE() { notify_assertion_violation(__FILE__, __LINE__, "UNEXPECTED CODE WAS REACHED."); exit(ERR_UNREACHABLE); } ((void) 0) | # define UNREACHABLE() { notify_assertion_violation(__FILE__, __LINE__, "UNEXPECTED CODE WAS REACHED."); invoke_exit_action(ERR_UNREACHABLE); } ((void) 0) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef Z3DEBUG | #ifdef Z3DEBUG | ||||||
| # define NOT_IMPLEMENTED_YET() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "NOT IMPLEMENTED YET!"); INVOKE_DEBUGGER();) | # define NOT_IMPLEMENTED_YET() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "NOT IMPLEMENTED YET!"); INVOKE_DEBUGGER();) | ||||||
| #else | #else | ||||||
| # define NOT_IMPLEMENTED_YET() { notify_assertion_violation(__FILE__, __LINE__, "NOT IMPLEMENTED YET!"); exit(ERR_NOT_IMPLEMENTED_YET); } ((void) 0) | # define NOT_IMPLEMENTED_YET() { notify_assertion_violation(__FILE__, __LINE__, "NOT IMPLEMENTED YET!"); invoke_exit_action(ERR_NOT_IMPLEMENTED_YET); } ((void) 0) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #define VERIFY(_x_) if (!(_x_)) {                                                       \ | #define VERIFY(_x_) if (!(_x_)) {                                                       \ | ||||||
|         notify_assertion_violation(__FILE__, __LINE__, "Failed to verify: " #_x_ "\n"); \ |         notify_assertion_violation(__FILE__, __LINE__, "Failed to verify: " #_x_ "\n"); \ | ||||||
|         exit(ERR_UNREACHABLE);                                                          \ |         invoke_exit_action(ERR_UNREACHABLE);                                                          \ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #define VERIFY_EQ(LHS, RHS)                                                                         \ | #define VERIFY_EQ(LHS, RHS)                                                                         \ | ||||||
|     if (!((LHS) == (RHS))) {                                                                        \ |     if (!((LHS) == (RHS))) {                                                                        \ | ||||||
|         notify_assertion_violation(__FILE__, __LINE__, "Failed to verify: " #LHS " == " #RHS "\n"); \ |         notify_assertion_violation(__FILE__, __LINE__, "Failed to verify: " #LHS " == " #RHS "\n"); \ | ||||||
|         std::cerr << "LHS value: " << (LHS) << "\nRHS value: " << (RHS) << "\n";                    \ |         std::cerr << "LHS value: " << (LHS) << "\nRHS value: " << (RHS) << "\n";                    \ | ||||||
|         DEBUG_CODE(INVOKE_DEBUGGER(););                                                             \ |         invoke_exit_action(ERR_UNREACHABLE);                                                                      \ | ||||||
|         exit(ERR_UNREACHABLE);                                                                      \ |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #define ENSURE(_x_) VERIFY(_x_) | #define ENSURE(_x_) VERIFY(_x_) | ||||||
|  |  | ||||||
|  | @ -472,7 +472,7 @@ public: | ||||||
|        that was already in the table. |        that was already in the table. | ||||||
|      */ |      */ | ||||||
|     data const & insert_if_not_there(data const & e) { |     data const & insert_if_not_there(data const & e) { | ||||||
|         entry * et; |         entry * et = nullptr; | ||||||
|         insert_if_not_there_core(e, et); |         insert_if_not_there_core(e, et); | ||||||
|         return et->get_data(); |         return et->get_data(); | ||||||
|     } |     } | ||||||
|  | @ -482,7 +482,7 @@ public: | ||||||
|        Return the entry that contains e. |        Return the entry that contains e. | ||||||
|     */ |     */ | ||||||
|     entry * insert_if_not_there2(data const & e) { |     entry * insert_if_not_there2(data const & e) { | ||||||
|         entry * et; |         entry * et = nullptr; | ||||||
|         insert_if_not_there_core(e, et); |         insert_if_not_there_core(e, et); | ||||||
|         return et; |         return et; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -142,7 +142,7 @@ static inline unsigned get_num_1bits(uint64_t v) { | ||||||
|     v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F; |     v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F; | ||||||
|     uint64_t r = (v * 0x0101010101010101) >> 56; |     uint64_t r = (v * 0x0101010101010101) >> 56; | ||||||
|     SASSERT(c == r); |     SASSERT(c == r); | ||||||
|     return (unsigned)r; |     return static_cast<unsigned>(r); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue