3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-03 11:25:40 +00:00
This commit is contained in:
Christoph M. Wintersteiger 2018-04-05 20:29:01 +01:00
commit 932ba15261
33 changed files with 594 additions and 312 deletions

View file

@ -34,7 +34,7 @@ endif()
################################################################################ ################################################################################
set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MAJOR 4)
set(Z3_VERSION_MINOR 6) set(Z3_VERSION_MINOR 6)
set(Z3_VERSION_PATCH 2) set(Z3_VERSION_PATCH 3)
set(Z3_VERSION_TWEAK 0) set(Z3_VERSION_TWEAK 0)
set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}")
set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified

View file

@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z
## Build status ## Build status
| Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | | Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI |
| ----------- | ----------- | ---------- | ---------- | --- | -------- | | ----------- | ----------- | ----------- | ---------- | ---------- | --- | -------- |
[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [![win64-badge](https://z3build.visualstudio.com/_apis/public/build/definitions/2e0aa542-a22c-4b1a-8dcd-3ebae8e12db4/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3)
[1]: #building-z3-on-windows-using-visual-studio-command-prompt [1]: #building-z3-on-windows-using-visual-studio-command-prompt
[2]: #building-z3-using-make-and-gccclang [2]: #building-z3-using-make-and-gccclang

View file

@ -920,6 +920,16 @@ void enum_sort_example() {
std::cout << "2: " << result_goal.as_expr() << std::endl; std::cout << "2: " << result_goal.as_expr() << std::endl;
} }
void tuple_example() {
std::cout << "tuple example\n";
context ctx;
const char * names[] = { "first", "second" };
sort sorts[2] = { ctx.int_sort(), ctx.bool_sort() };
func_decl_vector projs(ctx);
func_decl pair = ctx.tuple_sort("pair", 2, names, sorts, projs);
std::cout << pair << "\n";
}
void expr_vector_example() { void expr_vector_example() {
std::cout << "expr_vector example\n"; std::cout << "expr_vector example\n";
context c; context c;
@ -1179,6 +1189,7 @@ int main() {
incremental_example2(); std::cout << "\n"; incremental_example2(); std::cout << "\n";
incremental_example3(); std::cout << "\n"; incremental_example3(); std::cout << "\n";
enum_sort_example(); std::cout << "\n"; enum_sort_example(); std::cout << "\n";
tuple_example(); std::cout << "\n";
expr_vector_example(); std::cout << "\n"; expr_vector_example(); std::cout << "\n";
exists_expr_vector_example(); std::cout << "\n"; exists_expr_vector_example(); std::cout << "\n";
substitute_example(); std::cout << "\n"; substitute_example(); std::cout << "\n";

View file

@ -2452,7 +2452,6 @@ Z3_lbool ext_check(Z3_ext_context ctx) {
} }
printf("\n"); printf("\n");
} }
return result; return result;
} }
@ -2464,7 +2463,7 @@ void incremental_example1() {
Z3_context ctx = ext_ctx->m_context; Z3_context ctx = ext_ctx->m_context;
Z3_ast x, y, z, two, one; Z3_ast x, y, z, two, one;
unsigned c1, c2, c3, c4; unsigned c1, c2, c3, c4;
Z3_bool result; Z3_lbool result;
printf("\nincremental_example1\n"); printf("\nincremental_example1\n");
LOG_MSG("incremental_example1"); LOG_MSG("incremental_example1");

View file

@ -9,7 +9,7 @@ from mk_util import *
# Z3 Project definition # Z3 Project definition
def init_project_def(): def init_project_def():
set_version(4, 6, 2, 0) set_version(4, 6, 3, 0)
add_lib('util', []) add_lib('util', [])
add_lib('lp', ['util'], 'util/lp') add_lib('lp', ['util'], 'util/lp')
add_lib('polynomial', ['util'], 'math/polynomial') add_lib('polynomial', ['util'], 'math/polynomial')

View file

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

19
scripts/vsts-mac.sh Normal file
View file

@ -0,0 +1,19 @@
#!/bin/sh
cd ..
mkdir build
CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --java --python
cd build
make
make test-z3
make cpp_example
make c_example
# make java_example
# make python_example
./cpp_example
./test_capi
git clone https://github.com/z3prover/z3test.git z3test
ls
python z3test/scripts/test_benchmarks.py ./z3 ./z3test/regressions/smt2

49
scripts/vsts-vs2013.cmd Normal file
View file

@ -0,0 +1,49 @@
set
echo "Build"
md build
cd build
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64
cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../
nmake
if ERRORLEVEL 1 exit 1
rem echo "Test python bindings"
rem pushd python
rem python z3test.py z3
rem if ERRORLEVEL 1 exit 1
rem python z3test.py z3num
rem if ERRORLEVEL 1 exit 1
rem popd
echo "Build and run examples"
nmake cpp_example
examples\cpp_example_build_dir\cpp_example.exe
if ERRORLEVEL 1 exit 1
nmake c_example
examples\c_example_build_dir\c_example.exe
if ERRORLEVEL 1 exit 1
rem nmake java_example
rem java_example.exe
if ERRORLEVEL 1 exit 1
rem nmake dotnet_example
rem dotnet_example.exe
if ERRORLEVEL 1 exit 1
echo "Build and run unit tests"
nmake test-z3
rem TBD: test error level
rem test-z3.exe -a
cd ..
echo "Run regression tests"
git clone https://github.com/z3prover/z3test z3test
echo "test-benchmarks"
python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2
if ERRORLEVEL 1 exit 1
echo "benchmarks tested"

51
scripts/vsts-vs2017.cmd Normal file
View file

@ -0,0 +1,51 @@
rem Supply argument x64 or x86
echo "Build"
md build
cd build
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %1
cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../
nmake
if ERRORLEVEL 1 exit 1
if %1 == "x86" goto :BUILD_EXAMPLES
echo "Test python bindings"
pushd python
python z3test.py z3
if ERRORLEVEL 1 exit 1
python z3test.py z3num
if ERRORLEVEL 1 exit 1
popd
:BUILD_EXAMPLES
echo "Build and run examples"
nmake cpp_example
examples\cpp_example_build_dir\cpp_example.exe
if ERRORLEVEL 1 exit 1
nmake c_example
examples\c_example_build_dir\c_example.exe
if ERRORLEVEL 1 exit 1
rem nmake java_example
rem java_example.exe
if ERRORLEVEL 1 exit 1
rem nmake dotnet_example
rem dotnet_example.exe
if ERRORLEVEL 1 exit 1
echo "Build and run unit tests"
nmake test-z3
rem TBD: test error level
rem test-z3.exe -a
cd ..
echo "Run regression tests"
git clone https://github.com/z3prover/z3test z3test
echo "test-benchmarks"
python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2
if ERRORLEVEL 1 exit 1
echo "benchmarks tested"

View file

@ -34,6 +34,7 @@ Revision History:
#include "util/event_handler.h" #include "util/event_handler.h"
#include "cmd_context/tactic_manager.h" #include "cmd_context/tactic_manager.h"
#include "cmd_context/context_params.h" #include "cmd_context/context_params.h"
#include "cmd_context/cmd_context.h"
#include "api/api_polynomial.h" #include "api/api_polynomial.h"
#include "util/hashtable.h" #include "util/hashtable.h"
@ -53,6 +54,7 @@ namespace api {
context_params m_params; context_params m_params;
bool m_user_ref_count; //!< if true, the user is responsible for managing reference counters. bool m_user_ref_count; //!< if true, the user is responsible for managing reference counters.
scoped_ptr<ast_manager> m_manager; scoped_ptr<ast_manager> m_manager;
scoped_ptr<cmd_context> m_cmd;
add_plugins m_plugins; add_plugins m_plugins;
arith_util m_arith_util; arith_util m_arith_util;
@ -114,6 +116,7 @@ namespace api {
ast_manager & m() const { return *(m_manager.get()); } ast_manager & m() const { return *(m_manager.get()); }
context_params & params() { return m_params; } context_params & params() { return m_params; }
scoped_ptr<cmd_context>& cmd() { return m_cmd; }
bool produce_proofs() const { return m().proofs_enabled(); } bool produce_proofs() const { return m().proofs_enabled(); }
bool produce_models() const { return m_params.m_model; } bool produce_models() const { return m_params.m_model; }
bool produce_unsat_cores() const { return m_params.m_unsat_core; } bool produce_unsat_cores() const { return m_params.m_unsat_core; }

View file

@ -21,8 +21,11 @@ Revision History:
#include "api/api_context.h" #include "api/api_context.h"
#include "api/api_util.h" #include "api/api_util.h"
#include "cmd_context/cmd_context.h" #include "cmd_context/cmd_context.h"
#include "smt/smt_solver.h"
#include "parsers/smt2/smt2parser.h" #include "parsers/smt2/smt2parser.h"
#include "solver/solver_na2as.h" #include "solver/solver_na2as.h"
#include "tactic/portfolio/smt_strategic_solver.h"
extern "C" { extern "C" {
@ -117,4 +120,34 @@ extern "C" {
RETURN_Z3(r); RETURN_Z3(r);
Z3_CATCH_RETURN(nullptr); Z3_CATCH_RETURN(nullptr);
} }
Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context c, Z3_string str) {
std::stringstream ous;
Z3_TRY;
LOG_Z3_eval_smtlib2_string(c, str);
if (!mk_c(c)->cmd()) {
mk_c(c)->cmd() = alloc(cmd_context, false, &(mk_c(c)->m()));
mk_c(c)->cmd()->set_solver_factory(mk_smt_strategic_solver_factory());
}
scoped_ptr<cmd_context>& ctx = mk_c(c)->cmd();
std::string s(str);
std::istringstream is(s);
ctx->set_regular_stream(ous);
ctx->set_diagnostic_stream(ous);
try {
if (!parse_smt2_commands(*ctx.get(), is)) {
mk_c(c)->m_parser_error_buffer = ous.str();
SET_ERROR_CODE(Z3_PARSER_ERROR);
RETURN_Z3(mk_c(c)->mk_external_string(ous.str()));
}
}
catch (z3_exception& e) {
if (ous.str().empty()) ous << e.msg();
mk_c(c)->m_parser_error_buffer = ous.str();
SET_ERROR_CODE(Z3_PARSER_ERROR);
RETURN_Z3(mk_c(c)->mk_external_string(ous.str()));
}
RETURN_Z3(mk_c(c)->mk_external_string(ous.str()));
Z3_CATCH_RETURN(mk_c(c)->mk_external_string(ous.str()));
}
}; };

View file

@ -267,6 +267,15 @@ namespace z3 {
and in \c ts the predicates for testing if terms of the enumeration sort correspond to an enumeration. and in \c ts the predicates for testing if terms of the enumeration sort correspond to an enumeration.
*/ */
sort enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts); sort enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts);
/**
\brief Return a tuple constructor.
\c name is the name of the returned constructor,
\c n are the number of arguments, \c names and \c sorts are their projected sorts.
\c projs is an output paramter. It contains the set of projection functions.
*/
func_decl tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs);
/** /**
\brief create an uninterpreted sort with the name given by the string or symbol. \brief create an uninterpreted sort with the name given by the string or symbol.
*/ */
@ -2432,6 +2441,19 @@ namespace z3 {
for (unsigned i = 0; i < n; i++) { cs.push_back(func_decl(*this, _cs[i])); ts.push_back(func_decl(*this, _ts[i])); } for (unsigned i = 0; i < n; i++) { cs.push_back(func_decl(*this, _cs[i])); ts.push_back(func_decl(*this, _ts[i])); }
return s; return s;
} }
inline func_decl context::tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs) {
array<Z3_symbol> _names(n);
array<Z3_sort> _sorts(n);
for (unsigned i = 0; i < n; i++) { _names[i] = Z3_mk_string_symbol(*this, names[i]); _sorts[i] = sorts[i]; }
array<Z3_func_decl> _projs(n);
Z3_symbol _name = Z3_mk_string_symbol(*this, name);
Z3_func_decl tuple;
sort _ignore_s = to_sort(*this, Z3_mk_tuple_sort(*this, _name, n, _names.ptr(), _sorts.ptr(), &tuple, _projs.ptr()));
check_error();
for (unsigned i = 0; i < n; i++) { projs.push_back(func_decl(*this, _projs[i])); }
return func_decl(*this, tuple);
}
inline sort context::uninterpreted_sort(char const* name) { inline sort context::uninterpreted_sort(char const* name) {
Z3_symbol _name = Z3_mk_string_symbol(*this, name); Z3_symbol _name = Z3_mk_string_symbol(*this, name);
return to_sort(*this, Z3_mk_uninterpreted_sort(*this, _name)); return to_sort(*this, Z3_mk_uninterpreted_sort(*this, _name));

View file

@ -3,11 +3,11 @@ Copyright (c) 2012 Microsoft Corporation
Module Name: Module Name:
IntNum.cs AlgebraicNum.cs
Abstract: Abstract:
Z3 Managed API: Int Numerals Z3 Managed API: Algebraic Numerals
Author: Author:

View file

@ -3,11 +3,11 @@ Copyright (c) 2012 Microsoft Corporation
Module Name: Module Name:
IntNum.cs BitVecNum.cs
Abstract: Abstract:
Z3 Managed API: Int Numerals Z3 Managed API: BitVec Numerals
Author: Author:

View file

@ -114,15 +114,26 @@ def _symbol2py(ctx, s):
# Hack for having nary functions that can receive one argument that is the # Hack for having nary functions that can receive one argument that is the
# list of arguments. # list of arguments.
# Use this when function takes a single list of arguments
def _get_args(args): def _get_args(args):
try: try:
if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
return args[0] return args[0]
elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)): elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)):
return [arg for arg in args[0]] return [arg for arg in args[0]]
else:
return args
except: # len is not necessarily defined when args is not a sequence (use reflection?)
return args
# Use this when function takes multiple arguments
def _get_args_ast_list(args):
try:
if isinstance(args, set) or isinstance(args, AstVector) or isinstance(args, tuple):
return [arg for arg in args]
else: else:
return args return args
except: # len is not necessarily defined when args is not a sequence (use reflection?) except:
return args return args
def _to_param_value(val): def _to_param_value(val):
@ -7943,8 +7954,10 @@ def AtLeast(*args):
return BoolRef(Z3_mk_atleast(ctx.ref(), sz, _args, k), ctx) return BoolRef(Z3_mk_atleast(ctx.ref(), sz, _args, k), ctx)
def _pb_args_coeffs(args): def _pb_args_coeffs(args, default_ctx = None):
args = _get_args(args) args = _get_args_ast_list(args)
if len(args) == 0:
return _get_ctx(default_ctx), 0, (Ast * 0)(), (ctypes.c_int * 0)()
args, coeffs = zip(*args) args, coeffs = zip(*args)
if __debug__: if __debug__:
_z3_assert(len(args) > 0, "Non empty list of arguments expected") _z3_assert(len(args) > 0, "Non empty list of arguments expected")
@ -7976,7 +7989,7 @@ def PbGe(args, k):
ctx, sz, _args, _coeffs = _pb_args_coeffs(args) ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx) return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx)
def PbEq(args, k): def PbEq(args, k, ctx = None):
"""Create a Pseudo-Boolean inequality k constraint. """Create a Pseudo-Boolean inequality k constraint.
>>> a, b, c = Bools('a b c') >>> a, b, c = Bools('a b c')

View file

@ -36,7 +36,7 @@ _z3_op_to_str = {
Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int', Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int',
Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store', Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store',
Z3_OP_CONST_ARRAY : 'K', Z3_OP_ARRAY_EXT : 'Ext', Z3_OP_CONST_ARRAY : 'K', Z3_OP_ARRAY_EXT : 'Ext',
Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe' Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe', Z3_OP_PB_EQ : 'PbEq'
} }
# List of infix operators # List of infix operators
@ -930,6 +930,8 @@ class Formatter:
return self.pp_pbcmp(a, d, f, xs) return self.pp_pbcmp(a, d, f, xs)
elif k == Z3_OP_PB_GE: elif k == Z3_OP_PB_GE:
return self.pp_pbcmp(a, d, f, xs) return self.pp_pbcmp(a, d, f, xs)
elif k == Z3_OP_PB_EQ:
return self.pp_pbcmp(a, d, f, xs)
elif z3.is_pattern(a): elif z3.is_pattern(a):
return self.pp_pattern(a, d, xs) return self.pp_pattern(a, d, xs)
elif self.is_infix(k): elif self.is_infix(k):

View file

@ -22,6 +22,7 @@ Notes:
#define Z3_H_ #define Z3_H_
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include "z3_macros.h" #include "z3_macros.h"
#include "z3_api.h" #include "z3_api.h"
#include "z3_ast_containers.h" #include "z3_ast_containers.h"

View file

@ -80,9 +80,9 @@ DEFINE_TYPE(Z3_rcf_num);
*/ */
/** /**
\brief Z3 Boolean type. It is just an alias for \c int. \brief Z3 Boolean type. It is just an alias for \c bool.
*/ */
typedef int Z3_bool; typedef bool Z3_bool;
/** /**
\brief Z3 string type. It is just an alias for \ccode{const char *}. \brief Z3 string type. It is just an alias for \ccode{const char *}.
@ -5209,6 +5209,17 @@ extern "C" {
Z3_func_decl const decls[]); Z3_func_decl const decls[]);
/**
\brief Parse and evaluate and SMT-LIB2 command sequence. The state from a previous call is saved so the next
evaluation builds on top of the previous call.
\returns output generated from processing commands.
def_API('Z3_eval_smtlib2_string', STRING, (_in(CONTEXT), _in(STRING),))
*/
Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context, Z3_string str);
/** /**
\brief Retrieve that last error message information generated from parsing. \brief Retrieve that last error message information generated from parsing.

View file

@ -630,6 +630,12 @@ struct z3_replayer::imp {
return m_int_arrays[idx].c_ptr(); return m_int_arrays[idx].c_ptr();
} }
bool * get_bool_array(unsigned pos) const {
check_arg(pos, UINT_ARRAY);
unsigned idx = static_cast<unsigned>(m_args[pos].m_uint);
return reinterpret_cast<bool*>(m_unsigned_arrays[idx].c_ptr());
}
Z3_symbol * get_symbol_array(unsigned pos) const { Z3_symbol * get_symbol_array(unsigned pos) const {
check_arg(pos, SYMBOL_ARRAY); check_arg(pos, SYMBOL_ARRAY);
unsigned idx = static_cast<unsigned>(m_args[pos].m_uint); unsigned idx = static_cast<unsigned>(m_args[pos].m_uint);
@ -761,6 +767,10 @@ int * z3_replayer::get_int_array(unsigned pos) const {
return m_imp->get_int_array(pos); return m_imp->get_int_array(pos);
} }
bool * z3_replayer::get_bool_array(unsigned pos) const {
return m_imp->get_bool_array(pos);
}
Z3_symbol * z3_replayer::get_symbol_array(unsigned pos) const { Z3_symbol * z3_replayer::get_symbol_array(unsigned pos) const {
return m_imp->get_symbol_array(pos); return m_imp->get_symbol_array(pos);
} }

View file

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

View file

@ -821,6 +821,10 @@ namespace datatype {
return d; return d;
} }
app* util::mk_is(func_decl * c, expr *f) {
return m.mk_app(get_constructor_is(c), 1, &f);
}
func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { func_decl * util::get_recognizer_constructor(func_decl * recognizer) const {
SASSERT(is_recognizer(recognizer)); SASSERT(is_recognizer(recognizer));
return to_func_decl(recognizer->get_parameter(0).get_ast()); return to_func_decl(recognizer->get_parameter(0).get_ast());

View file

@ -362,6 +362,7 @@ namespace datatype {
bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); }
bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
app* mk_is(func_decl * c, expr *f);
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty); unsigned get_datatype_num_constructors(sort * ty);
unsigned get_datatype_num_parameter_sorts(sort * ty); unsigned get_datatype_num_parameter_sorts(sort * ty);

View file

@ -23,6 +23,9 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
switch(f->get_decl_kind()) { switch(f->get_decl_kind()) {
case OP_DT_CONSTRUCTOR: return BR_FAILED; case OP_DT_CONSTRUCTOR: return BR_FAILED;
case OP_DT_RECOGNISER: case OP_DT_RECOGNISER:
SASSERT(num_args == 1);
result = m_util.mk_is(m_util.get_recognizer_constructor(f), args[0]);
return BR_REWRITE1;
case OP_DT_IS: case OP_DT_IS:
// //
// simplify is_cons(cons(x,y)) -> true // simplify is_cons(cons(x,y)) -> true

View file

@ -406,6 +406,7 @@ public:
void reset_user_tactics(); void reset_user_tactics();
void set_regular_stream(char const * name) { m_regular.set(name); } void set_regular_stream(char const * name) { m_regular.set(name); }
void set_regular_stream(std::ostream& out) { m_regular.set(out); } void set_regular_stream(std::ostream& out) { m_regular.set(out); }
void set_diagnostic_stream(std::ostream& out) { m_diagnostic.set(out); }
void set_diagnostic_stream(char const * name); void set_diagnostic_stream(char const * name);
std::ostream & regular_stream() override { return *m_regular; } std::ostream & regular_stream() override { return *m_regular; }
std::ostream & diagnostic_stream() override { return *m_diagnostic; } std::ostream & diagnostic_stream() override { return *m_diagnostic; }

View file

@ -255,12 +255,12 @@ public:
catch (const char *msg) { catch (const char *msg) {
throw interpolation_failure(msg); throw interpolation_failure(msg);
} }
catch (const iz3translation::unsupported &) { catch (const iz3translation::unsupported & ex) {
TRACE("iz3", tout << "unsupported\n";); TRACE("iz3", tout << "unsupported " << "\n";);
throw interpolation_error(); throw interpolation_error();
} }
catch (const iz3proof::proof_error &) { catch (const iz3proof::proof_error & ex) {
TRACE("iz3", tout << "proof error\n";); TRACE("iz3", tout << "proof error " << "\n";);
throw interpolation_error(); throw interpolation_error();
} }
profiling::timer_stop("Proof translation"); profiling::timer_stop("Proof translation");
@ -306,8 +306,8 @@ public:
catch (const char *msg) { catch (const char *msg) {
throw interpolation_failure(msg); throw interpolation_failure(msg);
} }
catch (const iz3translation::unsupported &) { catch (const iz3translation::unsupported & ex) {
TRACE("iz3", tout << "unsupported\n";); TRACE("iz3", tout << "unsupported " << "\n";);
throw interpolation_error(); throw interpolation_error();
} }
catch (const iz3proof::proof_error &) { catch (const iz3proof::proof_error &) {

View file

@ -2030,7 +2030,7 @@ public:
if(is_local(con)) if(is_local(con))
res = args[0]; res = args[0];
else else
throw_unsupported(con); throw_unsupported(proof);
break; break;
} }
case PR_COMMUTATIVITY: { case PR_COMMUTATIVITY: {

View file

@ -949,8 +949,9 @@ namespace smt2 {
check_duplicate(d, line, pos); check_duplicate(d, line, pos);
d->commit(pm()); d->commit(pm());
check_rparen_next("invalid end of datatype declaration, ')' expected"); check_rparen("invalid end of datatype declaration, ')' expected");
m_ctx.print_success(); m_ctx.print_success();
next();
} }

View file

@ -580,20 +580,20 @@ namespace smt {
case b_justification::BIN_CLAUSE: { case b_justification::BIN_CLAUSE: {
literal l2 = j.get_literal(); literal l2 = j.get_literal();
out << "bin-clause "; out << "bin-clause ";
display_literal(out, l2); display_literal_verbose(out, l2);
break; break;
} }
case b_justification::CLAUSE: { case b_justification::CLAUSE: {
clause * cls = j.get_clause(); clause * cls = j.get_clause();
out << "clause "; out << "clause ";
if (cls) display_literals(out, cls->get_num_literals(), cls->begin_literals()); if (cls) display_literals_verbose(out, cls->get_num_literals(), cls->begin_literals());
break; break;
} }
case b_justification::JUSTIFICATION: { case b_justification::JUSTIFICATION: {
out << "justification " << j.get_justification()->get_from_theory() << ": "; out << "justification " << j.get_justification()->get_from_theory() << ": ";
literal_vector lits; literal_vector lits;
const_cast<conflict_resolution&>(*m_conflict_resolution).justification2literals(j.get_justification(), lits); const_cast<conflict_resolution&>(*m_conflict_resolution).justification2literals(j.get_justification(), lits);
display_literals(out, lits); display_literals_verbose(out, lits);
break; break;
} }
default: default:

View file

@ -222,7 +222,7 @@ namespace smt {
final_check_status final_check_eh(bool full) { final_check_status final_check_eh(bool full) {
if (full) { if (full) {
IF_VERBOSE(100, verbose_stream() << "(smt.final-check \"quantifiers\")\n";); IF_VERBOSE(100, if (!m_quantifiers.empty()) verbose_stream() << "(smt.final-check \"quantifiers\")\n";);
final_check_status result = m_qi_queue.final_check_eh() ? FC_DONE : FC_CONTINUE; final_check_status result = m_qi_queue.final_check_eh() ? FC_DONE : FC_CONTINUE;
final_check_status presult = m_plugin->final_check_eh(full); final_check_status presult = m_plugin->final_check_eh(full);
if (presult != FC_DONE) if (presult != FC_DONE)

View file

@ -2404,8 +2404,7 @@ bool theory_seq::add_stoi_val_axiom(expr* e) {
lits.push_back(~is_digit(ith_char)); lits.push_back(~is_digit(ith_char));
nums.push_back(digit2int(ith_char)); nums.push_back(digit2int(ith_char));
} }
for (unsigned i = sz-1, c = 1; i > 0; c *= 10) { for (unsigned i = sz, c = 1; i-- > 0; c *= 10) {
--i;
coeff = m_autil.mk_int(c); coeff = m_autil.mk_int(c);
nums[i] = m_autil.mk_mul(coeff, nums[i].get()); nums[i] = m_autil.mk_mul(coeff, nums[i].get());
} }
@ -2414,9 +2413,10 @@ bool theory_seq::add_stoi_val_axiom(expr* e) {
lits.push_back(mk_eq(e, num, false)); lits.push_back(mk_eq(e, num, false));
++m_stats.m_add_axiom; ++m_stats.m_add_axiom;
m_new_propagation = true; m_new_propagation = true;
for (unsigned i = 0; i < lits.size(); ++i) { for (literal lit : lits) {
ctx.mark_as_relevant(lits[i]); ctx.mark_as_relevant(lit);
} }
TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";);
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
m_stoi_axioms.insert(val); m_stoi_axioms.insert(val);
m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_stoi_axioms, val)); m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_stoi_axioms, val));

View file

@ -50,6 +50,7 @@ namespace smt {
m_factory(nullptr), m_factory(nullptr),
m_unused_id(0), m_unused_id(0),
m_delayed_axiom_setup_terms(m), m_delayed_axiom_setup_terms(m),
m_delayed_assertions_todo(m),
tmpStringVarCount(0), tmpStringVarCount(0),
tmpXorVarCount(0), tmpXorVarCount(0),
tmpLenTestVarCount(0), tmpLenTestVarCount(0),
@ -169,6 +170,8 @@ namespace smt {
} }
void theory_str::assert_axiom(expr * _e) { void theory_str::assert_axiom(expr * _e) {
if (_e == nullptr)
return;
if (opt_VerifyFinalCheckProgress) { if (opt_VerifyFinalCheckProgress) {
finalCheckProgressIndicator = true; finalCheckProgressIndicator = true;
} }
@ -638,6 +641,7 @@ namespace smt {
return contains; return contains;
} }
// note, this invokes "special-case" handling for the start index being 0
app * theory_str::mk_indexof(expr * haystack, expr * needle) { app * theory_str::mk_indexof(expr * haystack, expr * needle) {
app * indexof = u.str.mk_index(haystack, needle, mk_int(0)); app * indexof = u.str.mk_index(haystack, needle, mk_int(0));
m_trail.push_back(indexof); m_trail.push_back(indexof);
@ -779,8 +783,8 @@ namespace smt {
ptr_vector<expr> childrenVector; ptr_vector<expr> childrenVector;
get_nodes_in_concat(concatAst, childrenVector); get_nodes_in_concat(concatAst, childrenVector);
expr_ref_vector items(m); expr_ref_vector items(m);
for (unsigned int i = 0; i < childrenVector.size(); i++) { for (auto el : childrenVector) {
items.push_back(mk_strlen(childrenVector.get(i))); items.push_back(mk_strlen(el));
} }
expr_ref lenAssert(ctx.mk_eq_atom(concat_length, m_autil.mk_add(items.size(), items.c_ptr())), m); expr_ref lenAssert(ctx.mk_eq_atom(concat_length, m_autil.mk_add(items.size(), items.c_ptr())), m);
assert_axiom(lenAssert); assert_axiom(lenAssert);
@ -792,7 +796,8 @@ namespace smt {
return !m_basicstr_axiom_todo.empty() || !m_str_eq_todo.empty() return !m_basicstr_axiom_todo.empty() || !m_str_eq_todo.empty()
|| !m_concat_axiom_todo.empty() || !m_concat_eval_todo.empty() || !m_concat_axiom_todo.empty() || !m_concat_eval_todo.empty()
|| !m_library_aware_axiom_todo.empty() || !m_library_aware_axiom_todo.empty()
|| !m_delayed_axiom_setup_terms.empty(); || !m_delayed_axiom_setup_terms.empty()
|| (search_started && !m_delayed_assertions_todo.empty())
; ;
} }
@ -800,66 +805,101 @@ namespace smt {
context & ctx = get_context(); context & ctx = get_context();
while (can_propagate()) { while (can_propagate()) {
TRACE("str", tout << "propagating..." << std::endl;); TRACE("str", tout << "propagating..." << std::endl;);
for (unsigned i = 0; i < m_basicstr_axiom_todo.size(); ++i) { while(true) {
instantiate_basic_string_axioms(m_basicstr_axiom_todo[i]); // this can potentially recursively activate itself
unsigned start_count = m_basicstr_axiom_todo.size();
ptr_vector<enode> axioms_tmp(m_basicstr_axiom_todo);
for (auto const& el : axioms_tmp) {
instantiate_basic_string_axioms(el);
}
unsigned end_count = m_basicstr_axiom_todo.size();
if (end_count > start_count) {
TRACE("str", tout << "new basic string axiom terms added -- checking again" << std::endl;);
continue;
} else {
break;
}
} }
m_basicstr_axiom_todo.reset(); m_basicstr_axiom_todo.reset();
TRACE("str", tout << "reset m_basicstr_axiom_todo" << std::endl;); TRACE("str", tout << "reset m_basicstr_axiom_todo" << std::endl;);
for (unsigned i = 0; i < m_str_eq_todo.size(); ++i) { for (auto const& pair : m_str_eq_todo) {
std::pair<enode*,enode*> pair = m_str_eq_todo[i];
enode * lhs = pair.first; enode * lhs = pair.first;
enode * rhs = pair.second; enode * rhs = pair.second;
handle_equality(lhs->get_owner(), rhs->get_owner()); handle_equality(lhs->get_owner(), rhs->get_owner());
} }
m_str_eq_todo.reset(); m_str_eq_todo.reset();
for (unsigned i = 0; i < m_concat_axiom_todo.size(); ++i) { for (auto const& el : m_concat_axiom_todo) {
instantiate_concat_axiom(m_concat_axiom_todo[i]); instantiate_concat_axiom(el);
} }
m_concat_axiom_todo.reset(); m_concat_axiom_todo.reset();
for (unsigned i = 0; i < m_concat_eval_todo.size(); ++i) { for (auto const& el : m_concat_eval_todo) {
try_eval_concat(m_concat_eval_todo[i]); try_eval_concat(el);
} }
m_concat_eval_todo.reset(); m_concat_eval_todo.reset();
for (unsigned i = 0; i < m_library_aware_axiom_todo.size(); ++i) { while(true) {
enode * e = m_library_aware_axiom_todo[i]; // Special handling: terms can recursively set up other terms
app * a = e->get_owner(); // (e.g. indexof can instantiate other indexof terms).
if (u.str.is_stoi(a)) { // - Copy the list so it can potentially be modified during setup.
instantiate_axiom_str_to_int(e); // - Don't clear this list if new ones are added in the process;
} else if (u.str.is_itos(a)) { // instead, set up all the new terms before proceeding.
instantiate_axiom_int_to_str(e); // TODO see if any other propagate() worklists need this kind of handling
} else if (u.str.is_at(a)) { // TODO we really only need to check the new ones on each pass
instantiate_axiom_CharAt(e); unsigned start_count = m_library_aware_axiom_todo.size();
} else if (u.str.is_prefix(a)) { ptr_vector<enode> axioms_tmp(m_library_aware_axiom_todo);
instantiate_axiom_prefixof(e); for (auto const& e : axioms_tmp) {
} else if (u.str.is_suffix(a)) { app * a = e->get_owner();
instantiate_axiom_suffixof(e); if (u.str.is_stoi(a)) {
} else if (u.str.is_contains(a)) { instantiate_axiom_str_to_int(e);
instantiate_axiom_Contains(e); } else if (u.str.is_itos(a)) {
} else if (u.str.is_index(a)) { instantiate_axiom_int_to_str(e);
instantiate_axiom_Indexof(e); } else if (u.str.is_at(a)) {
} else if (u.str.is_extract(a)) { instantiate_axiom_CharAt(e);
instantiate_axiom_Substr(e); } else if (u.str.is_prefix(a)) {
} else if (u.str.is_replace(a)) { instantiate_axiom_prefixof(e);
instantiate_axiom_Replace(e); } else if (u.str.is_suffix(a)) {
} else if (u.str.is_in_re(a)) { instantiate_axiom_suffixof(e);
instantiate_axiom_RegexIn(e); } else if (u.str.is_contains(a)) {
instantiate_axiom_Contains(e);
} else if (u.str.is_index(a)) {
instantiate_axiom_Indexof(e);
} else if (u.str.is_extract(a)) {
instantiate_axiom_Substr(e);
} else if (u.str.is_replace(a)) {
instantiate_axiom_Replace(e);
} else if (u.str.is_in_re(a)) {
instantiate_axiom_RegexIn(e);
} else {
TRACE("str", tout << "BUG: unhandled library-aware term " << mk_pp(e->get_owner(), get_manager()) << std::endl;);
NOT_IMPLEMENTED_YET();
}
}
unsigned end_count = m_library_aware_axiom_todo.size();
if (end_count > start_count) {
TRACE("str", tout << "new library-aware terms added during axiom setup -- checking again" << std::endl;);
continue;
} else { } else {
TRACE("str", tout << "BUG: unhandled library-aware term " << mk_pp(e->get_owner(), get_manager()) << std::endl;); break;
NOT_IMPLEMENTED_YET();
} }
} }
m_library_aware_axiom_todo.reset(); m_library_aware_axiom_todo.reset();
for (unsigned i = 0; i < m_delayed_axiom_setup_terms.size(); ++i) { for (auto el : m_delayed_axiom_setup_terms) {
// I think this is okay // I think this is okay
ctx.internalize(m_delayed_axiom_setup_terms[i].get(), false); ctx.internalize(el, false);
set_up_axioms(m_delayed_axiom_setup_terms[i].get()); set_up_axioms(el);
} }
m_delayed_axiom_setup_terms.reset(); m_delayed_axiom_setup_terms.reset();
if (search_started) {
for (auto const& el : m_delayed_assertions_todo) {
assert_axiom(el);
}
m_delayed_assertions_todo.reset();
}
} }
} }
@ -969,6 +1009,15 @@ namespace smt {
TRACE("str", tout << "set up basic string axioms on " << mk_pp(str->get_owner(), m) << std::endl;); TRACE("str", tout << "set up basic string axioms on " << mk_pp(str->get_owner(), m) << std::endl;);
{
sort * a_sort = m.get_sort(str->get_owner());
sort * str_sort = u.str.mk_string_sort();
if (a_sort != str_sort) {
TRACE("str", tout << "WARNING: not setting up string axioms on non-string term " << mk_pp(str->get_owner(), m) << std::endl;);
return;
}
}
// TESTING: attempt to avoid a crash here when a variable goes out of scope // TESTING: attempt to avoid a crash here when a variable goes out of scope
if (str->get_iscope_lvl() > ctx.get_scope_level()) { if (str->get_iscope_lvl() > ctx.get_scope_level()) {
TRACE("str", tout << "WARNING: skipping axiom setup on out-of-scope string term" << std::endl;); TRACE("str", tout << "WARNING: skipping axiom setup on out-of-scope string term" << std::endl;);
@ -977,6 +1026,7 @@ namespace smt {
// generate a stronger axiom for constant strings // generate a stronger axiom for constant strings
app * a_str = str->get_owner(); app * a_str = str->get_owner();
if (u.str.is_string(a_str)) { if (u.str.is_string(a_str)) {
expr_ref len_str(m); expr_ref len_str(m);
len_str = mk_strlen(a_str); len_str = mk_strlen(a_str);
@ -1204,6 +1254,12 @@ namespace smt {
contains_map.push_back(ex); contains_map.push_back(ex);
std::pair<expr*, expr*> key = std::pair<expr*, expr*>(str, substr); std::pair<expr*, expr*> key = std::pair<expr*, expr*>(str, substr);
contain_pair_bool_map.insert(str, substr, ex); contain_pair_bool_map.insert(str, substr, ex);
if (!contain_pair_idx_map.contains(str)) {
contain_pair_idx_map.insert(str, std::set<std::pair<expr*, expr*>>());
}
if (!contain_pair_idx_map.contains(substr)) {
contain_pair_idx_map.insert(substr, std::set<std::pair<expr*, expr*>>());
}
contain_pair_idx_map[str].insert(key); contain_pair_idx_map[str].insert(key);
contain_pair_idx_map[substr].insert(key); contain_pair_idx_map[substr].insert(key);
} }
@ -1294,91 +1350,102 @@ namespace smt {
expr_ref conclusion(m_autil.mk_ge(ex, zeroAst), m); expr_ref conclusion(m_autil.mk_ge(ex, zeroAst), m);
expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m); expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m);
SASSERT(containsAxiom); SASSERT(containsAxiom);
// we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent
m_delayed_axiom_setup_terms.push_back(containsAxiom); //m_delayed_axiom_setup_terms.push_back(containsAxiom);
} }
} }
void theory_str::instantiate_axiom_Indexof_extended(enode * e) { void theory_str::instantiate_axiom_Indexof_extended(enode * _e) {
context & ctx = get_context(); context & ctx = get_context();
ast_manager & m = get_manager(); ast_manager & m = get_manager();
app * expr = e->get_owner(); app * e = _e->get_owner();
if (axiomatized_terms.contains(expr)) { if (axiomatized_terms.contains(e)) {
TRACE("str", tout << "already set up extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;); TRACE("str", tout << "already set up extended str.indexof axiom for " << mk_pp(e, m) << std::endl;);
return; return;
} }
SASSERT(expr->get_num_args() == 3); SASSERT(e->get_num_args() == 3);
axiomatized_terms.insert(expr); axiomatized_terms.insert(e);
TRACE("str", tout << "instantiate extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;); TRACE("str", tout << "instantiate extended str.indexof axiom for " << mk_pp(e, m) << std::endl;);
// ------------------------------------------------------------------------------- // str.indexof(H, N, i):
// if (arg[2] >= length(arg[0])) // ite2 // i < 0 --> -1
// resAst = -1 // i == 0 --> str.indexof(H, N, 0)
// else // i >= len(H) --> -1
// args[0] = prefix . suffix // 0 < i < len(H) -->
// /\ indexAst = indexof(suffix, arg[1]) // H = hd ++ tl
// /\ args[2] = len(prefix) // len(hd) = i
// /\ if (indexAst == -1) resAst = indexAst // ite3 // str.indexof(tl, N, 0)
// else resAst = args[2] + indexAst
// -------------------------------------------------------------------------------
expr_ref resAst(mk_int_var("res"), m); expr * H; // "haystack"
expr_ref indexAst(mk_int_var("index"), m); expr * N; // "needle"
expr_ref prefix(mk_str_var("prefix"), m); expr * i; // start index
expr_ref suffix(mk_str_var("suffix"), m); u.str.is_index(e, H, N, i);
expr_ref prefixLen(mk_strlen(prefix), m);
expr_ref zeroAst(mk_int(0), m);
expr_ref negOneAst(mk_int(-1), m);
expr_ref ite3(m.mk_ite( expr_ref minus_one(m_autil.mk_numeral(rational::minus_one(), true), m);
ctx.mk_eq_atom(indexAst, negOneAst), expr_ref zero(m_autil.mk_numeral(rational::zero(), true), m);
ctx.mk_eq_atom(resAst, negOneAst),
ctx.mk_eq_atom(resAst, m_autil.mk_add(expr->get_arg(2), indexAst))
),m);
expr_ref_vector ite2ElseItems(m); // case split
ite2ElseItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(prefix, suffix)));
ite2ElseItems.push_back(ctx.mk_eq_atom(indexAst, mk_indexof(suffix, expr->get_arg(1))));
ite2ElseItems.push_back(ctx.mk_eq_atom(expr->get_arg(2), prefixLen));
ite2ElseItems.push_back(ite3);
expr_ref ite2Else(mk_and(ite2ElseItems), m);
SASSERT(ite2Else);
expr_ref ite2(m.mk_ite( // case 1: i < 0
//m_autil.mk_ge(expr->get_arg(2), mk_strlen(expr->get_arg(0))), {
m_autil.mk_ge(m_autil.mk_add(expr->get_arg(2), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), zeroAst), expr_ref premise(m_autil.mk_le(i, minus_one), m);
ctx.mk_eq_atom(resAst, negOneAst), expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m);
ite2Else assert_implication(premise, conclusion);
), m); }
SASSERT(ite2);
expr_ref ite1(m.mk_ite( // case 2: i = 0
//m_autil.mk_lt(expr->get_arg(2), zeroAst), {
mk_not(m, m_autil.mk_ge(expr->get_arg(2), zeroAst)), expr_ref premise(ctx.mk_eq_atom(i, zero), m);
ctx.mk_eq_atom(resAst, mk_indexof(expr->get_arg(0), expr->get_arg(1))), // reduction to simpler case
ite2 expr_ref conclusion(ctx.mk_eq_atom(e, mk_indexof(H, N)), m);
), m); assert_implication(premise, conclusion);
SASSERT(ite1); }
assert_axiom(ite1); // case 3: i >= len(H)
{
//expr_ref _premise(m_autil.mk_ge(i, mk_strlen(H)), m);
//expr_ref premise(_premise);
//th_rewriter rw(m);
//rw(premise);
expr_ref premise(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero), m);
expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m);
assert_implication(premise, conclusion);
}
// case 4: 0 < i < len(H)
{
expr_ref premise1(m_autil.mk_gt(i, zero), m);
//expr_ref premise2(m_autil.mk_lt(i, mk_strlen(H)), m);
expr_ref premise2(m.mk_not(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero)), m);
expr_ref _premise(m.mk_and(premise1, premise2), m);
expr_ref premise(_premise);
th_rewriter rw(m);
rw(premise);
expr_ref reduceTerm(ctx.mk_eq_atom(expr, resAst), m); expr_ref hd(mk_str_var("hd"), m);
SASSERT(reduceTerm); expr_ref tl(mk_str_var("tl"), m);
assert_axiom(reduceTerm);
expr_ref_vector conclusion_terms(m);
conclusion_terms.push_back(ctx.mk_eq_atom(H, mk_concat(hd, tl)));
conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(hd), i));
conclusion_terms.push_back(ctx.mk_eq_atom(e, mk_indexof(tl, N)));
expr_ref conclusion(mk_and(conclusion_terms), m);
assert_implication(premise, conclusion);
}
{ {
// heuristic: integrate with str.contains information // heuristic: integrate with str.contains information
// (but don't introduce it if it isn't already in the instance) // (but don't introduce it if it isn't already in the instance)
expr_ref haystack(expr->get_arg(0), m), needle(expr->get_arg(1), m), startIdx(expr->get_arg(2), m);
// (H contains N) <==> (H indexof N, i) >= 0 // (H contains N) <==> (H indexof N, i) >= 0
expr_ref premise(u.str.mk_contains(haystack, needle), m); expr_ref premise(u.str.mk_contains(H, N), m);
ctx.internalize(premise, false); ctx.internalize(premise, false);
expr_ref conclusion(m_autil.mk_ge(expr, zeroAst), m); expr_ref conclusion(m_autil.mk_ge(e, zero), m);
expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m); expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m);
SASSERT(containsAxiom); SASSERT(containsAxiom);
// we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent
m_delayed_axiom_setup_terms.push_back(containsAxiom); m_delayed_assertions_todo.push_back(containsAxiom);
} }
} }
@ -2378,9 +2445,8 @@ namespace smt {
} else { } else {
expr_ref_vector items(m); expr_ref_vector items(m);
int pos = 0; int pos = 0;
std::map<expr*, expr*>::iterator itor = resolvedMap.begin(); for (auto itor : resolvedMap) {
for (; itor != resolvedMap.end(); ++itor) { items.push_back(ctx.mk_eq_atom(itor.first, itor.second));
items.push_back(ctx.mk_eq_atom(itor->first, itor->second));
pos += 1; pos += 1;
} }
expr_ref premise(mk_and(items), m); expr_ref premise(mk_and(items), m);
@ -2556,8 +2622,7 @@ namespace smt {
context & ctx = get_context(); context & ctx = get_context();
// pull each literal out of the arrangement disjunction // pull each literal out of the arrangement disjunction
literal_vector ls; literal_vector ls;
for (unsigned i = 0; i < terms.size(); ++i) { for (expr * e : terms) {
expr * e = terms.get(i);
literal l = ctx.get_literal(e); literal l = ctx.get_literal(e);
ls.push_back(l); ls.push_back(l);
} }
@ -4495,8 +4560,7 @@ namespace smt {
} }
} }
for (std::list<unsigned int>::iterator itor = overlapLen.begin(); itor != overlapLen.end(); itor++) { for (unsigned int overLen : overlapLen) {
unsigned int overLen = *itor;
zstring prefix = str1Value.extract(0, str1Len - overLen); zstring prefix = str1Value.extract(0, str1Len - overLen);
zstring suffix = str2Value.extract(overLen, str2Len - overLen); zstring suffix = str2Value.extract(overLen, str2Len - overLen);
@ -4577,10 +4641,10 @@ namespace smt {
TRACE("str", tout << "concat = " << mk_pp(concat, mgr) << ", unroll = " << mk_pp(unroll, mgr) << std::endl;); TRACE("str", tout << "concat = " << mk_pp(concat, mgr) << ", unroll = " << mk_pp(unroll, mgr) << std::endl;);
std::pair<expr*, expr*> key = std::make_pair(concat, unroll);
expr_ref toAssert(mgr); expr_ref toAssert(mgr);
expr * _toAssert;
if (concat_eq_unroll_ast_map.find(key) == concat_eq_unroll_ast_map.end()) { if (!concat_eq_unroll_ast_map.find(concat, unroll, _toAssert)) {
expr_ref arg1(to_app(concat)->get_arg(0), mgr); expr_ref arg1(to_app(concat)->get_arg(0), mgr);
expr_ref arg2(to_app(concat)->get_arg(1), mgr); expr_ref arg2(to_app(concat)->get_arg(1), mgr);
expr_ref r1(to_app(unroll)->get_arg(0), mgr); expr_ref r1(to_app(unroll)->get_arg(0), mgr);
@ -4631,9 +4695,9 @@ namespace smt {
toAssert = mgr.mk_and(opAnd1, opAnd2); toAssert = mgr.mk_and(opAnd1, opAnd2);
m_trail.push_back(toAssert); m_trail.push_back(toAssert);
concat_eq_unroll_ast_map[key] = toAssert; concat_eq_unroll_ast_map.insert(concat, unroll, toAssert);
} else { } else {
toAssert = concat_eq_unroll_ast_map[key]; toAssert = _toAssert;
} }
assert_axiom(toAssert); assert_axiom(toAssert);
@ -4917,11 +4981,10 @@ namespace smt {
expr_ref_vector litems(m); expr_ref_vector litems(m);
if (contain_pair_idx_map.find(varNode) != contain_pair_idx_map.end()) { if (contain_pair_idx_map.contains(varNode)) {
std::set<std::pair<expr*, expr*> >::iterator itor1 = contain_pair_idx_map[varNode].begin(); for (auto entry : contain_pair_idx_map[varNode]) {
for (; itor1 != contain_pair_idx_map[varNode].end(); ++itor1) { expr * strAst = entry.first;
expr * strAst = itor1->first; expr * substrAst = entry.second;
expr * substrAst = itor1->second;
expr * boolVar = nullptr; expr * boolVar = nullptr;
if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) { if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) {
@ -4979,23 +5042,18 @@ namespace smt {
// collect eqc concat // collect eqc concat
std::set<expr*> eqcConcats; std::set<expr*> eqcConcats;
get_concats_in_eqc(substrAst, eqcConcats); get_concats_in_eqc(substrAst, eqcConcats);
for (std::set<expr*>::iterator concatItor = eqcConcats.begin(); for (expr * aConcat : eqcConcats) {
concatItor != eqcConcats.end(); concatItor++) {
expr_ref_vector constList(m); expr_ref_vector constList(m);
bool counterEgFound = false; bool counterEgFound = false;
// get constant strings in concat
expr * aConcat = *concatItor;
get_const_str_asts_in_node(aConcat, constList); get_const_str_asts_in_node(aConcat, constList);
for (expr_ref_vector::iterator cstItor = constList.begin(); for (auto const& cst : constList) {
cstItor != constList.end(); cstItor++) {
zstring pieceStr; zstring pieceStr;
u.str.is_string(*cstItor, pieceStr); u.str.is_string(cst, pieceStr);
if (!strConst.contains(pieceStr)) { if (!strConst.contains(pieceStr)) {
counterEgFound = true; counterEgFound = true;
if (aConcat != substrAst) { if (aConcat != substrAst) {
litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); litems.push_back(ctx.mk_eq_atom(substrAst, aConcat));
} }
//implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx));
implyR = mk_not(m, boolVar); implyR = mk_not(m, boolVar);
break; break;
} }
@ -5054,11 +5112,10 @@ namespace smt {
ast_manager & m = get_manager(); ast_manager & m = get_manager();
expr_ref_vector litems(m); expr_ref_vector litems(m);
if (contain_pair_idx_map.find(varNode) != contain_pair_idx_map.end()) { if (contain_pair_idx_map.contains(varNode)) {
std::set<std::pair<expr*, expr*> >::iterator itor1 = contain_pair_idx_map[varNode].begin(); for (auto entry : contain_pair_idx_map[varNode]) {
for (; itor1 != contain_pair_idx_map[varNode].end(); ++itor1) { expr * strAst = entry.first;
expr * strAst = itor1->first; expr * substrAst = entry.second;
expr * substrAst = itor1->second;
expr * boolVar = nullptr; expr * boolVar = nullptr;
if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) { if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) {
@ -5087,17 +5144,16 @@ namespace smt {
zstring strConst; zstring strConst;
u.str.is_string(strValue, strConst); u.str.is_string(strValue, strConst);
// iterate eqc (also eqc-to-be) of substr // iterate eqc (also eqc-to-be) of substr
for (expr_ref_vector::iterator itAst = willEqClass.begin(); itAst != willEqClass.end(); itAst++) { for (auto itAst : willEqClass) {
bool counterEgFound = false; bool counterEgFound = false;
if (u.str.is_concat(to_app(*itAst))) { if (u.str.is_concat(to_app(itAst))) {
expr_ref_vector constList(m); expr_ref_vector constList(m);
// get constant strings in concat // get constant strings in concat
app * aConcat = to_app(*itAst); app * aConcat = to_app(itAst);
get_const_str_asts_in_node(aConcat, constList); get_const_str_asts_in_node(aConcat, constList);
for (expr_ref_vector::iterator cstItor = constList.begin(); for (auto cst : constList) {
cstItor != constList.end(); cstItor++) {
zstring pieceStr; zstring pieceStr;
u.str.is_string(*cstItor, pieceStr); u.str.is_string(cst, pieceStr);
if (!strConst.contains(pieceStr)) { if (!strConst.contains(pieceStr)) {
TRACE("str", tout << "Inconsistency found!" << std::endl;); TRACE("str", tout << "Inconsistency found!" << std::endl;);
counterEgFound = true; counterEgFound = true;
@ -5122,7 +5178,7 @@ namespace smt {
} }
bool theory_str::in_contain_idx_map(expr * n) { bool theory_str::in_contain_idx_map(expr * n) {
return contain_pair_idx_map.find(n) != contain_pair_idx_map.end(); return contain_pair_idx_map.contains(n);
} }
void theory_str::check_contain_by_eq_nodes(expr * n1, expr * n2) { void theory_str::check_contain_by_eq_nodes(expr * n1, expr * n2) {
@ -5130,12 +5186,9 @@ namespace smt {
ast_manager & m = get_manager(); ast_manager & m = get_manager();
if (in_contain_idx_map(n1) && in_contain_idx_map(n2)) { if (in_contain_idx_map(n1) && in_contain_idx_map(n2)) {
std::set<std::pair<expr*, expr*> >::iterator keysItor1 = contain_pair_idx_map[n1].begin(); for (auto const& key1 : contain_pair_idx_map[n1]) {
std::set<std::pair<expr*, expr*> >::iterator keysItor2;
for (; keysItor1 != contain_pair_idx_map[n1].end(); keysItor1++) {
// keysItor1 is on set {<.., n1>, ..., <n1, ...>, ...} // keysItor1 is on set {<.., n1>, ..., <n1, ...>, ...}
std::pair<expr*, expr*> key1 = *keysItor1; //std::pair<expr*, expr*> key1 = *keysItor1;
if (key1.first == n1 && key1.second == n2) { if (key1.first == n1 && key1.second == n2) {
expr_ref implyL(m); expr_ref implyL(m);
expr_ref implyR(contain_pair_bool_map[key1], m); expr_ref implyR(contain_pair_bool_map[key1], m);
@ -5147,10 +5200,10 @@ namespace smt {
} }
} }
for (keysItor2 = contain_pair_idx_map[n2].begin(); //for (keysItor2 = contain_pair_idx_map[n2].begin(); keysItor2 != contain_pair_idx_map[n2].end(); keysItor2++) {
keysItor2 != contain_pair_idx_map[n2].end(); keysItor2++) { for (auto const& key2 : contain_pair_idx_map[n2]) {
// keysItor2 is on set {<.., n2>, ..., <n2, ...>, ...} // keysItor2 is on set {<.., n2>, ..., <n2, ...>, ...}
std::pair<expr*, expr*> key2 = *keysItor2; //std::pair<expr*, expr*> key2 = *keysItor2;
// skip if the pair is eq // skip if the pair is eq
if (key1 == key2) { if (key1 == key2) {
continue; continue;
@ -5244,10 +5297,12 @@ namespace smt {
// * key1.first = key2.first // * key1.first = key2.first
// check eqc(key1.second) and eqc(key2.second) // check eqc(key1.second) and eqc(key2.second)
// ----------------------------------------------------------- // -----------------------------------------------------------
expr_ref_vector::iterator eqItorSub1 = subAst1Eqc.begin(); //expr_ref_vector::iterator eqItorSub1 = subAst1Eqc.begin();
for (; eqItorSub1 != subAst1Eqc.end(); eqItorSub1++) { //for (; eqItorSub1 != subAst1Eqc.end(); eqItorSub1++) {
expr_ref_vector::iterator eqItorSub2 = subAst2Eqc.begin(); for (auto eqSubVar1 : subAst1Eqc) {
for (; eqItorSub2 != subAst2Eqc.end(); eqItorSub2++) { //expr_ref_vector::iterator eqItorSub2 = subAst2Eqc.begin();
//for (; eqItorSub2 != subAst2Eqc.end(); eqItorSub2++) {
for (auto eqSubVar2 : subAst2Eqc) {
// ------------ // ------------
// key1.first = key2.first /\ containPairBoolMap[<eqc(key1.second), eqc(key2.second)>] // key1.first = key2.first /\ containPairBoolMap[<eqc(key1.second), eqc(key2.second)>]
// ==> (containPairBoolMap[key1] --> containPairBoolMap[key2]) // ==> (containPairBoolMap[key1] --> containPairBoolMap[key2])
@ -5257,11 +5312,11 @@ namespace smt {
if (n1 != n2) { if (n1 != n2) {
litems3.push_back(ctx.mk_eq_atom(n1, n2)); litems3.push_back(ctx.mk_eq_atom(n1, n2));
} }
expr * eqSubVar1 = *eqItorSub1;
if (eqSubVar1 != subAst1) { if (eqSubVar1 != subAst1) {
litems3.push_back(ctx.mk_eq_atom(subAst1, eqSubVar1)); litems3.push_back(ctx.mk_eq_atom(subAst1, eqSubVar1));
} }
expr * eqSubVar2 = *eqItorSub2;
if (eqSubVar2 != subAst2) { if (eqSubVar2 != subAst2) {
litems3.push_back(ctx.mk_eq_atom(subAst2, eqSubVar2)); litems3.push_back(ctx.mk_eq_atom(subAst2, eqSubVar2));
} }
@ -5282,11 +5337,11 @@ namespace smt {
if (n1 != n2) { if (n1 != n2) {
litems4.push_back(ctx.mk_eq_atom(n1, n2)); litems4.push_back(ctx.mk_eq_atom(n1, n2));
} }
expr * eqSubVar1 = *eqItorSub1;
if (eqSubVar1 != subAst1) { if (eqSubVar1 != subAst1) {
litems4.push_back(ctx.mk_eq_atom(subAst1, eqSubVar1)); litems4.push_back(ctx.mk_eq_atom(subAst1, eqSubVar1));
} }
expr * eqSubVar2 = *eqItorSub2;
if (eqSubVar2 != subAst2) { if (eqSubVar2 != subAst2) {
litems4.push_back(ctx.mk_eq_atom(subAst2, eqSubVar2)); litems4.push_back(ctx.mk_eq_atom(subAst2, eqSubVar2));
} }
@ -5394,20 +5449,18 @@ namespace smt {
// * key1.second = key2.second // * key1.second = key2.second
// check eqc(key1.first) and eqc(key2.first) // check eqc(key1.first) and eqc(key2.first)
// ----------------------------------------------------------- // -----------------------------------------------------------
expr_ref_vector::iterator eqItorStr1 = str1Eqc.begin(); for (auto const& eqStrVar1 : str1Eqc) {
for (; eqItorStr1 != str1Eqc.end(); eqItorStr1++) { for (auto const& eqStrVar2 : str2Eqc) {
expr_ref_vector::iterator eqItorStr2 = str2Eqc.begin();
for (; eqItorStr2 != str2Eqc.end(); eqItorStr2++) {
{ {
expr_ref_vector litems3(m); expr_ref_vector litems3(m);
if (n1 != n2) { if (n1 != n2) {
litems3.push_back(ctx.mk_eq_atom(n1, n2)); litems3.push_back(ctx.mk_eq_atom(n1, n2));
} }
expr * eqStrVar1 = *eqItorStr1;
if (eqStrVar1 != str1) { if (eqStrVar1 != str1) {
litems3.push_back(ctx.mk_eq_atom(str1, eqStrVar1)); litems3.push_back(ctx.mk_eq_atom(str1, eqStrVar1));
} }
expr * eqStrVar2 = *eqItorStr2;
if (eqStrVar2 != str2) { if (eqStrVar2 != str2) {
litems3.push_back(ctx.mk_eq_atom(str2, eqStrVar2)); litems3.push_back(ctx.mk_eq_atom(str2, eqStrVar2));
} }
@ -5430,11 +5483,9 @@ namespace smt {
if (n1 != n2) { if (n1 != n2) {
litems4.push_back(ctx.mk_eq_atom(n1, n2)); litems4.push_back(ctx.mk_eq_atom(n1, n2));
} }
expr * eqStrVar1 = *eqItorStr1;
if (eqStrVar1 != str1) { if (eqStrVar1 != str1) {
litems4.push_back(ctx.mk_eq_atom(str1, eqStrVar1)); litems4.push_back(ctx.mk_eq_atom(str1, eqStrVar1));
} }
expr *eqStrVar2 = *eqItorStr2;
if (eqStrVar2 != str2) { if (eqStrVar2 != str2) {
litems4.push_back(ctx.mk_eq_atom(str2, eqStrVar2)); litems4.push_back(ctx.mk_eq_atom(str2, eqStrVar2));
} }
@ -5480,8 +5531,7 @@ namespace smt {
expr * constStrAst = (constStrAst_1 != nullptr) ? constStrAst_1 : constStrAst_2; expr * constStrAst = (constStrAst_1 != nullptr) ? constStrAst_1 : constStrAst_2;
TRACE("str", tout << "eqc of n1 is {"; TRACE("str", tout << "eqc of n1 is {";
for (expr_ref_vector::iterator it = willEqClass.begin(); it != willEqClass.end(); ++it) { for (expr * el : willEqClass) {
expr * el = *it;
tout << " " << mk_pp(el, m); tout << " " << mk_pp(el, m);
} }
tout << std::endl; tout << std::endl;
@ -5494,12 +5544,11 @@ namespace smt {
// step 1: we may have constant values for Contains checks now // step 1: we may have constant values for Contains checks now
if (constStrAst != nullptr) { if (constStrAst != nullptr) {
expr_ref_vector::iterator itAst = willEqClass.begin(); for (auto a : willEqClass) {
for (; itAst != willEqClass.end(); itAst++) { if (a == constStrAst) {
if (*itAst == constStrAst) {
continue; continue;
} }
check_contain_by_eqc_val(*itAst, constStrAst); check_contain_by_eqc_val(a, constStrAst);
} }
} else { } else {
// no concrete value to be put in eqc, solely based on context // no concrete value to be put in eqc, solely based on context
@ -5511,9 +5560,8 @@ namespace smt {
// * "EQC(M) U EQC(concat(..., "jio", ...))" as substr and // * "EQC(M) U EQC(concat(..., "jio", ...))" as substr and
// * If strAst registered has an eqc constant in the context // * If strAst registered has an eqc constant in the context
// ------------------------------------------------------------- // -------------------------------------------------------------
expr_ref_vector::iterator itAst = willEqClass.begin(); for (auto a : willEqClass) {
for (; itAst != willEqClass.end(); ++itAst) { check_contain_by_substr(a, willEqClass);
check_contain_by_substr(*itAst, willEqClass);
} }
} }
@ -5530,12 +5578,8 @@ namespace smt {
// (9) containPairBoolMap[<eqc(y), eqc(x)>] /\ m = n ==> (b1 -> b2) // (9) containPairBoolMap[<eqc(y), eqc(x)>] /\ m = n ==> (b1 -> b2)
// ------------------------------------------ // ------------------------------------------
expr_ref_vector::iterator varItor1 = willEqClass.begin(); for (auto varAst1 : willEqClass) {
for (; varItor1 != willEqClass.end(); ++varItor1) { for (auto varAst2 : willEqClass) {
expr * varAst1 = *varItor1;
expr_ref_vector::iterator varItor2 = varItor1;
for (; varItor2 != willEqClass.end(); ++varItor2) {
expr * varAst2 = *varItor2;
check_contain_by_eq_nodes(varAst1, varAst2); check_contain_by_eq_nodes(varAst1, varAst2);
} }
} }
@ -5849,11 +5893,10 @@ namespace smt {
std::map<expr*, expr*> & concatAliasMap, std::map<expr*, expr*> & varConstMap, std::map<expr*, expr*> & concatAliasMap, std::map<expr*, expr*> & varConstMap,
std::map<expr*, expr*> & concatConstMap, std::map<expr*, std::map<expr*, int> > & varEqConcatMap) { std::map<expr*, expr*> & concatConstMap, std::map<expr*, std::map<expr*, int> > & varEqConcatMap) {
std::map<expr*, std::map<std::vector<expr*>, std::set<expr*> > > groundedMap; std::map<expr*, std::map<std::vector<expr*>, std::set<expr*> > > groundedMap;
theory_str_contain_pair_bool_map_t::iterator containItor = contain_pair_bool_map.begin(); for (auto const& kv : contain_pair_bool_map) {
for (; containItor != contain_pair_bool_map.end(); containItor++) { expr* containBoolVar = kv.get_value();
expr* containBoolVar = containItor->get_value(); expr* str = kv.get_key1();
expr* str = containItor->get_key1(); expr* subStr = kv.get_key2();
expr* subStr = containItor->get_key2();
expr* strDeAlias = dealias_node(str, varAliasMap, concatAliasMap); expr* strDeAlias = dealias_node(str, varAliasMap, concatAliasMap);
expr* subStrDeAlias = dealias_node(subStr, varAliasMap, concatAliasMap); expr* subStrDeAlias = dealias_node(subStr, varAliasMap, concatAliasMap);
@ -6455,7 +6498,7 @@ namespace smt {
} else { } else {
expr_ref_vector::iterator itor = eqNodeSet.begin(); expr_ref_vector::iterator itor = eqNodeSet.begin();
for (; itor != eqNodeSet.end(); itor++) { for (; itor != eqNodeSet.end(); itor++) {
if (regex_in_var_reg_str_map.find(*itor) != regex_in_var_reg_str_map.end()) { if (regex_in_var_reg_str_map.contains(*itor)) {
std::set<zstring>::iterator strItor = regex_in_var_reg_str_map[*itor].begin(); std::set<zstring>::iterator strItor = regex_in_var_reg_str_map[*itor].begin();
for (; strItor != regex_in_var_reg_str_map[*itor].end(); strItor++) { for (; strItor != regex_in_var_reg_str_map[*itor].end(); strItor++) {
zstring regStr = *strItor; zstring regStr = *strItor;
@ -6914,12 +6957,12 @@ namespace smt {
if (!map_effectively_empty) { if (!map_effectively_empty) {
map_effectively_empty = true; map_effectively_empty = true;
ptr_vector<expr> indicator_set = fvar_lenTester_map[v]; if (fvar_lenTester_map.contains(v)) {
for (ptr_vector<expr>::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { for (expr * indicator : fvar_lenTester_map[v]) {
expr * indicator = *it; if (internal_variable_set.contains(indicator)) {
if (internal_variable_set.find(indicator) != internal_variable_set.end()) { map_effectively_empty = false;
map_effectively_empty = false; break;
break; }
} }
} }
} }
@ -6964,16 +7007,19 @@ namespace smt {
} }
// now create a fake length tester over this finite disjunction of lengths // now create a fake length tester over this finite disjunction of lengths
fvar_len_count_map[v] = 1; fvar_len_count_map.insert(v, 1);
unsigned int testNum = fvar_len_count_map[v]; unsigned int testNum = fvar_len_count_map[v];
expr_ref indicator(mk_internal_lenTest_var(v, testNum), m); expr_ref indicator(mk_internal_lenTest_var(v, testNum), m);
SASSERT(indicator); SASSERT(indicator);
m_trail.push_back(indicator); m_trail.push_back(indicator);
if (!fvar_lenTester_map.contains(v)) {
fvar_lenTester_map.insert(v, ptr_vector<expr>());
}
fvar_lenTester_map[v].shrink(0); fvar_lenTester_map[v].shrink(0);
fvar_lenTester_map[v].push_back(indicator); fvar_lenTester_map[v].push_back(indicator);
lenTester_fvar_map[indicator] = v; lenTester_fvar_map.insert(indicator, v);
expr_ref_vector orList(m); expr_ref_vector orList(m);
expr_ref_vector andList(m); expr_ref_vector andList(m);
@ -7040,7 +7086,12 @@ namespace smt {
} }
} }
} else { } else {
int lenTesterCount = fvar_lenTester_map[fVar].size(); int lenTesterCount;
if (fvar_lenTester_map.contains(fVar)) {
lenTesterCount = fvar_lenTester_map[fVar].size();
} else {
lenTesterCount = 0;
}
expr * effectiveLenInd = nullptr; expr * effectiveLenInd = nullptr;
zstring effectiveLenIndiStr = ""; zstring effectiveLenIndiStr = "";
@ -7411,8 +7462,7 @@ namespace smt {
if (is_app(ex)) { if (is_app(ex)) {
app * ap = to_app(ex); app * ap = to_app(ex);
// TODO indexof2/lastindexof if (u.str.is_index(ap)) {
if (u.str.is_index(ap) /* || is_Indexof2(ap) || is_LastIndexof(ap) */) {
m_library_aware_axiom_todo.push_back(n); m_library_aware_axiom_todo.push_back(n);
} else if (u.str.is_stoi(ap)) { } else if (u.str.is_stoi(ap)) {
TRACE("str", tout << "found string-integer conversion term: " << mk_pp(ex, get_manager()) << std::endl;); TRACE("str", tout << "found string-integer conversion term: " << mk_pp(ex, get_manager()) << std::endl;);
@ -7945,11 +7995,12 @@ namespace smt {
// Step 1: get variables / concat AST appearing in the context // Step 1: get variables / concat AST appearing in the context
// the thing we iterate over should just be variable_set - internal_variable_set // the thing we iterate over should just be variable_set - internal_variable_set
// so we avoid computing the set difference (but this might be slower) // so we avoid computing the set difference (but this might be slower)
for(obj_hashtable<expr>::iterator it = variable_set.begin(); it != variable_set.end(); ++it) { for (expr* var : variable_set) {
expr* var = *it; //for(obj_hashtable<expr>::iterator it = variable_set.begin(); it != variable_set.end(); ++it) {
//expr* var = *it;
if (internal_variable_set.find(var) == internal_variable_set.end()) { if (internal_variable_set.find(var) == internal_variable_set.end()) {
TRACE("str", tout << "new variable: " << mk_pp(var, m) << std::endl;); TRACE("str", tout << "new variable: " << mk_pp(var, m) << std::endl;);
strVarMap[*it] = 1; strVarMap[var] = 1;
} }
} }
classify_ast_by_type_in_positive_context(strVarMap, concatMap, unrollMap); classify_ast_by_type_in_positive_context(strVarMap, concatMap, unrollMap);
@ -8977,12 +9028,12 @@ namespace smt {
CTRACE("str", needToAssignFreeVars, CTRACE("str", needToAssignFreeVars,
tout << "Need to assign values to the following free variables:" << std::endl; tout << "Need to assign values to the following free variables:" << std::endl;
for (std::set<expr*>::iterator itx = free_variables.begin(); itx != free_variables.end(); ++itx) { for (expr* v : free_variables) {
tout << mk_ismt2_pp(*itx, m) << std::endl; tout << mk_ismt2_pp(v, m) << std::endl;
} }
tout << "freeVar_map has the following entries:" << std::endl; tout << "freeVar_map has the following entries:" << std::endl;
for (std::map<expr*, int>::iterator fvIt = freeVar_map.begin(); fvIt != freeVar_map.end(); fvIt++) { for (auto const& kv : freeVar_map) {
expr * var = fvIt->first; expr * var = kv.first;
tout << mk_ismt2_pp(var, m) << std::endl; tout << mk_ismt2_pp(var, m) << std::endl;
} }
); );
@ -9360,13 +9411,12 @@ namespace smt {
// check whether any value tester is actually in scope // check whether any value tester is actually in scope
TRACE("str", tout << "checking scope of previous value testers" << std::endl;); TRACE("str", tout << "checking scope of previous value testers" << std::endl;);
bool map_effectively_empty = true; bool map_effectively_empty = true;
if (fvar_valueTester_map[freeVar].find(len) != fvar_valueTester_map[freeVar].end()) { if (fvar_valueTester_map.contains(freeVar) &&
fvar_valueTester_map[freeVar].find(len) != fvar_valueTester_map[freeVar].end()) {
// there's *something* in the map, but check its scope // there's *something* in the map, but check its scope
svector<std::pair<int, expr*> > entries = fvar_valueTester_map[freeVar][len]; for (auto const& entry : fvar_valueTester_map[freeVar][len]) {
for (svector<std::pair<int,expr*> >::iterator it = entries.begin(); it != entries.end(); ++it) {
std::pair<int,expr*> entry = *it;
expr * aTester = entry.second; expr * aTester = entry.second;
if (internal_variable_set.find(aTester) == internal_variable_set.end()) { if (!internal_variable_set.contains(aTester)) {
TRACE("str", tout << mk_pp(aTester, m) << " out of scope" << std::endl;); TRACE("str", tout << mk_pp(aTester, m) << " out of scope" << std::endl;);
} else { } else {
TRACE("str", tout << mk_pp(aTester, m) << " in scope" << std::endl;); TRACE("str", tout << mk_pp(aTester, m) << " in scope" << std::endl;);
@ -9381,6 +9431,9 @@ namespace smt {
int tries = 0; int tries = 0;
expr * val_indicator = mk_internal_valTest_var(freeVar, len, tries); expr * val_indicator = mk_internal_valTest_var(freeVar, len, tries);
valueTester_fvar_map.insert(val_indicator, freeVar); valueTester_fvar_map.insert(val_indicator, freeVar);
if (!fvar_valueTester_map.contains(freeVar)) {
fvar_valueTester_map.insert(freeVar, std::map<int, svector<std::pair<int, expr*> > >());
}
fvar_valueTester_map[freeVar][len].push_back(std::make_pair(sLevel, val_indicator)); fvar_valueTester_map[freeVar][len].push_back(std::make_pair(sLevel, val_indicator));
print_value_tester_list(fvar_valueTester_map[freeVar][len]); print_value_tester_list(fvar_valueTester_map[freeVar][len]);
return gen_val_options(freeVar, len_indicator, val_indicator, len_valueStr, tries); return gen_val_options(freeVar, len_indicator, val_indicator, len_valueStr, tries);
@ -9396,7 +9449,7 @@ namespace smt {
expr * aTester = fvar_valueTester_map[freeVar][len][i].second; expr * aTester = fvar_valueTester_map[freeVar][len][i].second;
// it's probably worth checking scope here, actually // it's probably worth checking scope here, actually
if (internal_variable_set.find(aTester) == internal_variable_set.end()) { if (!internal_variable_set.contains(aTester)) {
TRACE("str", tout << "value tester " << mk_pp(aTester, m) << " out of scope, skipping" << std::endl;); TRACE("str", tout << "value tester " << mk_pp(aTester, m) << " out of scope, skipping" << std::endl;);
continue; continue;
} }
@ -9721,8 +9774,8 @@ namespace smt {
int dist = opt_LCMUnrollStep; int dist = opt_LCMUnrollStep;
expr_ref_vector litems(mgr); expr_ref_vector litems(mgr);
expr_ref moreAst(mk_string("more"), mgr); expr_ref moreAst(mk_string("more"), mgr);
for (std::set<expr*>::iterator itor = unrolls.begin(); itor != unrolls.end(); itor++) { for (expr * e : unrolls) {
expr_ref item(ctx.mk_eq_atom(var, *itor), mgr); expr_ref item(ctx.mk_eq_atom(var, e), mgr);
TRACE("str", tout << "considering unroll " << mk_pp(item, mgr) << std::endl;); TRACE("str", tout << "considering unroll " << mk_pp(item, mgr) << std::endl;);
litems.push_back(item); litems.push_back(item);
} }
@ -9731,10 +9784,8 @@ namespace smt {
ptr_vector<expr> outOfScopeTesters; ptr_vector<expr> outOfScopeTesters;
for (ptr_vector<expr>::iterator it = unroll_tries_map[var][unrolls].begin(); for (expr * tester : unroll_tries_map[var][unrolls]) {
it != unroll_tries_map[var][unrolls].end(); ++it) { bool inScope = internal_unrollTest_vars.contains(tester);
expr * tester = *it;
bool inScope = (internal_unrollTest_vars.find(tester) != internal_unrollTest_vars.end());
TRACE("str", tout << "unroll test var " << mk_pp(tester, mgr) TRACE("str", tout << "unroll test var " << mk_pp(tester, mgr)
<< (inScope ? " in scope" : " out of scope") << (inScope ? " in scope" : " out of scope")
<< std::endl;); << std::endl;);
@ -9743,12 +9794,10 @@ namespace smt {
} }
} }
for (ptr_vector<expr>::iterator it = outOfScopeTesters.begin(); for (expr* e : outOfScopeTesters) {
it != outOfScopeTesters.end(); ++it) { unroll_tries_map[var][unrolls].erase(e);
unroll_tries_map[var][unrolls].erase(*it);
} }
if (unroll_tries_map[var][unrolls].size() == 0) { if (unroll_tries_map[var][unrolls].size() == 0) {
unroll_tries_map[var][unrolls].push_back(mk_unroll_test_var()); unroll_tries_map[var][unrolls].push_back(mk_unroll_test_var());
} }
@ -10264,14 +10313,14 @@ namespace smt {
// assume empty and find a counterexample // assume empty and find a counterexample
map_effectively_empty = true; map_effectively_empty = true;
ptr_vector<expr> indicator_set = fvar_lenTester_map[freeVar]; if (fvar_lenTester_map.contains(freeVar)) {
for (ptr_vector<expr>::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { for (expr * indicator : fvar_lenTester_map[freeVar]) {
expr * indicator = *it; if (internal_variable_set.find(indicator) != internal_variable_set.end()) {
if (internal_variable_set.find(indicator) != internal_variable_set.end()) { TRACE("str", tout <<"found active internal variable " << mk_ismt2_pp(indicator, m)
TRACE("str", tout <<"found active internal variable " << mk_ismt2_pp(indicator, m) << " in fvar_lenTester_map[freeVar]" << std::endl;);
<< " in fvar_lenTester_map[freeVar]" << std::endl;); map_effectively_empty = false;
map_effectively_empty = false; break;
break; }
} }
} }
CTRACE("str", map_effectively_empty, tout << "all variables in fvar_lenTester_map[freeVar] out of scope" << std::endl;); CTRACE("str", map_effectively_empty, tout << "all variables in fvar_lenTester_map[freeVar] out of scope" << std::endl;);
@ -10288,6 +10337,9 @@ namespace smt {
SASSERT(indicator); SASSERT(indicator);
// since the map is "effectively empty", we can remove those variables that have left scope... // since the map is "effectively empty", we can remove those variables that have left scope...
if (!fvar_lenTester_map.contains(freeVar)) {
fvar_lenTester_map.insert(freeVar, ptr_vector<expr>());
}
fvar_lenTester_map[freeVar].shrink(0); fvar_lenTester_map[freeVar].shrink(0);
fvar_lenTester_map[freeVar].push_back(indicator); fvar_lenTester_map[freeVar].push_back(indicator);
lenTester_fvar_map.insert(indicator, freeVar); lenTester_fvar_map.insert(indicator, freeVar);
@ -10300,7 +10352,12 @@ namespace smt {
expr * effectiveLenInd = nullptr; expr * effectiveLenInd = nullptr;
zstring effectiveLenIndiStr(""); zstring effectiveLenIndiStr("");
int lenTesterCount = (int) fvar_lenTester_map[freeVar].size(); int lenTesterCount;
if (fvar_lenTester_map.contains(freeVar)) {
lenTesterCount = fvar_lenTester_map[freeVar].size();
} else {
lenTesterCount = 0;
}
TRACE("str", TRACE("str",
tout << lenTesterCount << " length testers in fvar_lenTester_map[" << mk_pp(freeVar, m) << "]:" << std::endl; tout << lenTesterCount << " length testers in fvar_lenTester_map[" << mk_pp(freeVar, m) << "]:" << std::endl;
@ -10437,14 +10494,14 @@ namespace smt {
void theory_str::process_free_var(std::map<expr*, int> & freeVar_map) { void theory_str::process_free_var(std::map<expr*, int> & freeVar_map) {
context & ctx = get_context(); context & ctx = get_context();
std::set<expr*> eqcRepSet; obj_hashtable<expr> eqcRepSet;
std::set<expr*> leafVarSet; obj_hashtable<expr> leafVarSet;
std::map<int, std::set<expr*> > aloneVars; std::map<int, obj_hashtable<expr> > aloneVars;
for (std::map<expr*, int>::iterator fvIt = freeVar_map.begin(); fvIt != freeVar_map.end(); fvIt++) { for (auto const& kv : freeVar_map) {
expr * freeVar = fvIt->first; expr * freeVar = kv.first;
// skip all regular expression vars // skip all regular expression vars
if (regex_variable_set.find(freeVar) != regex_variable_set.end()) { if (regex_variable_set.contains(freeVar)) {
continue; continue;
} }
@ -10454,10 +10511,10 @@ namespace smt {
get_var_in_eqc(freeVar, eqVarSet); get_var_in_eqc(freeVar, eqVarSet);
bool duplicated = false; bool duplicated = false;
expr * dupVar = nullptr; expr * dupVar = nullptr;
for (std::set<expr*>::iterator itorEqv = eqVarSet.begin(); itorEqv != eqVarSet.end(); itorEqv++) { for (expr* eq : eqVarSet) {
if (eqcRepSet.find(*itorEqv) != eqcRepSet.end()) { if (eqcRepSet.contains(eq)) {
duplicated = true; duplicated = true;
dupVar = *itorEqv; dupVar = eq;
break; break;
} }
} }
@ -10470,13 +10527,9 @@ namespace smt {
} }
} }
for (std::set<expr*>::iterator fvIt = eqcRepSet.begin(); fvIt != eqcRepSet.end(); fvIt++) { for (expr * freeVar : eqcRepSet) {
bool standAlone = true;
expr * freeVar = *fvIt;
// has length constraint initially // has length constraint initially
if (input_var_in_len.find(freeVar) != input_var_in_len.end()) { bool standAlone = !input_var_in_len.contains(freeVar);
standAlone = false;
}
// iterate parents // iterate parents
if (standAlone) { if (standAlone) {
// I hope this works! // I hope this works!
@ -10507,25 +10560,19 @@ namespace smt {
} }
} }
for(std::set<expr*>::iterator itor1 = leafVarSet.begin(); for (expr* lv : leafVarSet) {
itor1 != leafVarSet.end(); ++itor1) { expr * toAssert = gen_len_val_options_for_free_var(lv, nullptr, "");
expr * toAssert = gen_len_val_options_for_free_var(*itor1, nullptr, "");
// gen_len_val_options_for_free_var() can legally return NULL, // gen_len_val_options_for_free_var() can legally return NULL,
// as methods that it calls may assert their own axioms instead. // as methods that it calls may assert their own axioms instead.
if (toAssert != nullptr) { if (toAssert) assert_axiom(toAssert);
assert_axiom(toAssert);
}
} }
for (std::map<int, std::set<expr*> >::iterator mItor = aloneVars.begin(); for (auto const& kv : aloneVars) {
mItor != aloneVars.end(); ++mItor) { for (expr* av : kv.second) {
std::set<expr*>::iterator itor2 = mItor->second.begin(); expr * toAssert = gen_len_val_options_for_free_var(av, nullptr, "");
for(; itor2 != mItor->second.end(); ++itor2) {
expr * toAssert = gen_len_val_options_for_free_var(*itor2, nullptr, "");
// same deal with returning a NULL axiom here // same deal with returning a NULL axiom here
if(toAssert != nullptr) { if (toAssert) assert_axiom(toAssert);
assert_axiom(toAssert);
}
} }
} }
} }

View file

@ -262,6 +262,7 @@ protected:
ptr_vector<enode> m_concat_axiom_todo; ptr_vector<enode> m_concat_axiom_todo;
ptr_vector<enode> m_string_constant_length_todo; ptr_vector<enode> m_string_constant_length_todo;
ptr_vector<enode> m_concat_eval_todo; ptr_vector<enode> m_concat_eval_todo;
expr_ref_vector m_delayed_assertions_todo;
// enode lists for library-aware/high-level string terms (e.g. substr, contains) // enode lists for library-aware/high-level string terms (e.g. substr, contains)
ptr_vector<enode> m_library_aware_axiom_todo; ptr_vector<enode> m_library_aware_axiom_todo;
@ -295,33 +296,30 @@ protected:
obj_hashtable<expr> input_var_in_len; obj_hashtable<expr> input_var_in_len;
obj_map<expr, unsigned int> fvar_len_count_map; obj_map<expr, unsigned int> fvar_len_count_map;
std::map<expr*, ptr_vector<expr> > fvar_lenTester_map; obj_map<expr, ptr_vector<expr> > fvar_lenTester_map;
obj_map<expr, expr*> lenTester_fvar_map; obj_map<expr, expr*> lenTester_fvar_map;
// TBD: need to replace by obj_map for determinism
std::map<expr*, std::map<int, svector<std::pair<int, expr*> > > > fvar_valueTester_map; obj_map<expr, std::map<int, svector<std::pair<int, expr*> > > > fvar_valueTester_map;
obj_map<expr, expr*> valueTester_fvar_map; obj_map<expr, expr*> valueTester_fvar_map;
obj_map<expr, int_vector> val_range_map; obj_map<expr, int_vector> val_range_map;
// This can't be an expr_ref_vector because the constructor is wrong, // This can't be an expr_ref_vector because the constructor is wrong,
// we would need to modify the allocator so we pass in ast_manager // we would need to modify the allocator so we pass in ast_manager
// TBD: need to replace by obj_map for determinism obj_map<expr, std::map<std::set<expr*>, ptr_vector<expr> > > unroll_tries_map;
std::map<expr*, std::map<std::set<expr*>, ptr_vector<expr> > > unroll_tries_map;
obj_map<expr, expr*> unroll_var_map; obj_map<expr, expr*> unroll_var_map;
// TBD: need to replace by obj_pair_map for determinism obj_pair_map<expr, expr, expr*> concat_eq_unroll_ast_map;
std::map<std::pair<expr*, expr*>, expr*> concat_eq_unroll_ast_map;
expr_ref_vector contains_map; expr_ref_vector contains_map;
theory_str_contain_pair_bool_map_t contain_pair_bool_map; theory_str_contain_pair_bool_map_t contain_pair_bool_map;
//obj_map<expr, obj_pair_set<expr, expr> > contain_pair_idx_map; obj_map<expr, std::set<std::pair<expr*, expr*> > > contain_pair_idx_map;
std::map<expr*, std::set<std::pair<expr*, expr*> > > contain_pair_idx_map;
// TBD: do a curried map for determinism. // TBD: do a curried map for determinism.
std::map<std::pair<expr*, zstring>, expr*> regex_in_bool_map; std::map<std::pair<expr*, zstring>, expr*> regex_in_bool_map;
// TBD: need to replace by obj_map for determinism obj_map<expr, std::set<zstring> > regex_in_var_reg_str_map;
std::map<expr*, std::set<zstring> > regex_in_var_reg_str_map;
obj_map<expr, nfa> regex_nfa_cache; // Regex term --> NFA obj_map<expr, nfa> regex_nfa_cache; // Regex term --> NFA
svector<char> char_set; svector<char> char_set;

View file

@ -600,9 +600,8 @@ public:
core_hashtable& operator|=(core_hashtable const& other) { core_hashtable& operator|=(core_hashtable const& other) {
if (this == &other) return *this; if (this == &other) return *this;
iterator i = other.begin(), e = other.end(); for (const data& d : other) {
for (; i != e; ++i) { insert(d);
insert(*i);
} }
return *this; return *this;
} }
@ -610,10 +609,9 @@ public:
core_hashtable& operator&=(core_hashtable const& other) { core_hashtable& operator&=(core_hashtable const& other) {
if (this == &other) return *this; if (this == &other) return *this;
core_hashtable copy(*this); core_hashtable copy(*this);
iterator i = copy.begin(), e = copy.end(); for (const data& d : copy) {
for (; i != e; ++i) { if (!other.contains(d)) {
if (!other.contains(*i)) { remove(d);
remove(*i);
} }
} }
return *this; return *this;
@ -622,9 +620,8 @@ public:
core_hashtable& operator=(core_hashtable const& other) { core_hashtable& operator=(core_hashtable const& other) {
if (this == &other) return *this; if (this == &other) return *this;
reset(); reset();
iterator i = other.begin(), e = other.end(); for (const data& d : other) {
for (; i != e; ++i) { insert(d);
insert(*i);
} }
return *this; return *this;
} }