diff --git a/CMakeLists.txt b/CMakeLists.txt index 715679957..69a0ca123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ endif() # Project version ################################################################################ set(Z3_VERSION_MAJOR 4) -set(Z3_VERSION_MINOR 5) +set(Z3_VERSION_MINOR 6) set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") @@ -257,6 +257,46 @@ list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/src" "${CMAKE_SOURCE_DIR}/src" ) + +################################################################################ +# Linux specific configuration +################################################################################ +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # Try to detect if it is necessary to link against librt. + # Note that glibc < 2.17 required librt to be linked to use clock_gettime() + # and friends. + set(CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE + " + #include + int main() { + timespec res; + int result = clock_gettime(CLOCK_REALTIME, &res); + return result == 0; + } + " + ) + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_NO_REQUIRE_LIBRT + ) + if (NOT CLOCK_GETTIME_NO_REQUIRE_LIBRT) + # Try again with librt + message(STATUS "Failed to link against clock_gettime(), trying with librt") + set(CMAKE_REQUIRED_LIBRARIES_OLD "${CMAKE_REQUIRED_LIBRARIES}") + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} rt") + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_REQUIRES_LIBRT + ) + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_OLD}") + if (CLOCK_GETTIME_REQUIRES_LIBRT) + list(APPEND Z3_DEPENDENT_LIBS "rt") + else() + message(FATAL_ERROR "Failed to link against clock_gettime()") + endif() + endif() +endif() + ################################################################################ # GNU multiple precision library support ################################################################################ diff --git a/README-CMake.md b/README-CMake.md index 0d323e08f..1b1f72729 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -5,7 +5,7 @@ of the project written in the ``CMakeLists.txt`` files and emits a build system for that project of your choice using one of CMake's "generators". This allows CMake to support many different platforms and build tools. You can run ``cmake --help`` to see the list of supported "generators" -on your platform. Example generators include "UNIX Makfiles" and "Visual Studio +on your platform. Example generators include "UNIX Makefiles" and "Visual Studio 12 2013". ## Getting started @@ -44,7 +44,7 @@ cmake -G "Unix Makefiles" ../ make -j4 # Replace 4 with an appropriate number ``` -Note that on some platforms "Unix Makesfiles" is the default generator so on those +Note that on some platforms "Unix Makefiles" is the default generator so on those platforms you don't need to pass ``-G "Unix Makefiles"`` command line option to ``cmake``. diff --git a/RELEASE_NOTES b/RELEASE_NOTES index ec05160da..5ce4d2682 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,7 +1,12 @@ RELEASE NOTES -Version 4.5.x +Version 4.6.0 ============= + +- New requirements: + - C++11 capable compiler to build Z3. + - C++ API now requires C++11 or newer. + - New features (including): - A new string solver from University of Waterloo - A new linear real arithmetic solver @@ -10,6 +15,10 @@ Version 4.5.x issuing the command (get-objectives). Pareto front objectives are accessed by issuing multiple (check-sat) calls until it returns unsat. +- Removed features: + - Removed support for SMT-LIB 1.x + + Version 4.5.0 ============= @@ -45,10 +54,9 @@ Version 4.5.0 over compound formulas, introduce a fresh predicate whose arguments are the relevant free variables in the formula and add a rule that uses the fresh predicate in the head and formula in the body. - - minimization of unsat cores is avaialble as an option for the SAT and SMT cores. + - Minimization of unsat cores is available as an option for the SAT and SMT cores. By setting smt.core.minimize=true resp. sat.core.minimize=true - cores produced by these modules are minimized. - + cores produced by these modules are minimized. - A multitude of bugs has been fixed. @@ -704,7 +712,7 @@ The following bugs are fixed in this release: bvshl when using a shift amount that evaluates to the length of the bit-vector. Thanks to Trevor Hansen and Robert Brummayer. -- Incorrect NNF conversion in linear quantifier elimniation routines. +- Incorrect NNF conversion in linear quantifier elimination routines. Thanks to Josh Berdine. - Missing constant folding of extraction for large bit-vectors. diff --git a/cmake/Z3Config.cmake.in b/cmake/Z3Config.cmake.in index e7f604591..dbd63b103 100644 --- a/cmake/Z3Config.cmake.in +++ b/cmake/Z3Config.cmake.in @@ -2,7 +2,7 @@ # @AUTO_GEN_MSG@ # # This file is intended to be consumed by clients who wish to use Z3 from CMake. -# It can be use by doing `find_package(Z3 config)` from within a +# It can be used by doing `find_package(Z3 config)` from within a # `CMakeLists.txt` file. If CMake doesn't find this package automatically you # can give it a hint by passing `-DZ3_DIR=` to the CMake invocation where # `` is the path to the directory containing this file. diff --git a/contrib/suppressions/sanitizers/README.md b/contrib/suppressions/sanitizers/README.md index f76f920b2..1d7cd0ac8 100644 --- a/contrib/suppressions/sanitizers/README.md +++ b/contrib/suppressions/sanitizers/README.md @@ -1,4 +1,4 @@ -# Sanitizer supression files +# Sanitizer suppression files This directory contains files used to suppress ASan/LSan/UBSan warnings/errors. diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index a944f2c65..a1a9e64bd 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -226,12 +226,14 @@ try: website_dox_substitutions = {} bullet_point_prefix='\n - ' if Z3PY_ENABLED: + print("Python documentation enabled") website_dox_substitutions['PYTHON_API'] = ( '{prefix}Python API ' '(also available in pydoc format)' ).format( prefix=bullet_point_prefix) else: + print("Python documentation disabled") website_dox_substitutions['PYTHON_API'] = '' if DOTNET_ENABLED: website_dox_substitutions['DOTNET_API'] = ( @@ -250,7 +252,7 @@ try: website_dox_substitutions['JAVA_API'] = '' if ML_ENABLED: website_dox_substitutions['OCAML_API'] = ( - 'ML/OCaml API' + '{prefix}ML/OCaml API' ).format( prefix=bullet_point_prefix) else: @@ -316,7 +318,7 @@ try: if ML_ENABLED: ml_output_dir = os.path.join(OUTPUT_DIRECTORY, 'html', 'ml') mk_dir(ml_output_dir) - if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, doc_path('../src/api/ml/z3enums.mli'), doc_path('../src/api/ml/z3.mli')]) != 0: + if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, '%s/api/ml/z3enums.mli' % BUILD_DIR, '%s/api/ml/z3.mli' % BUILD_DIR]) != 0: print("ERROR: ocamldoc failed.") exit(1) print("Generated ML/OCaml documentation.") @@ -326,3 +328,4 @@ except Exception: exctype, value = sys.exc_info()[:2] print("ERROR: failed to generate documentation: %s" % value) exit(1) + diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index d60604924..0a41d6a93 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -13,6 +13,22 @@ find_package(Z3 # use this option. NO_DEFAULT_PATH ) + +################################################################################ +# Z3 C++ API bindings require C++11 +################################################################################ +if ("${CMAKE_VERSION}" VERSION_LESS "3.1") + # Legacy CMake support + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + else() + message(FATAL_ERROR "Setting C++ version to C++11 not supported for \"${CMAKE_CXX_COMPILER_ID}\"") + endif() +else () + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif () + message(STATUS "Z3_FOUND: ${Z3_FOUND}") message(STATUS "Found Z3 ${Z3_VERSION_STRING}") message(STATUS "Z3_DIR: ${Z3_DIR}") diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 035d032bc..df977268a 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1138,8 +1138,11 @@ static void parse_example() { decls.push_back(c.function("a", 0, 0, B)); expr a = c.parse_string("(assert a)", sorts, decls); std::cout << a << "\n"; + + // expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); } + int main() { try { diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index f6d515389..b947928a7 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -395,11 +395,10 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) t_name = Z3_mk_string_symbol(ctx, "T"); - Z3_parse_smtlib_string(ctx, - "(benchmark comm :formula (forall (x T) (y T) (= (f x y) (f y x))))", + q = Z3_parse_smtlib2_string(ctx, + "(assert (forall ((x T) (y T)) (= (f x y) (f y x))))", 1, &t_name, &t, 1, &f_name, &f); - q = Z3_get_smtlib_formula(ctx, 0); printf("assert axiom:\n%s\n", Z3_ast_to_string(ctx, q)); Z3_solver_assert(ctx, s, q); } @@ -1547,7 +1546,7 @@ void two_contexts_example1() } /** - \brief Demonstrates how error codes can be read insted of registering an error handler. + \brief Demonstrates how error codes can be read instead of registering an error handler. */ void error_code_example1() { @@ -1632,35 +1631,6 @@ void error_code_example2() { } } -/** - \brief Demonstrates how to use the SMTLIB parser. - */ -void parser_example1() -{ - Z3_context ctx = mk_context(); - Z3_solver s = mk_solver(ctx); - unsigned i, num_formulas; - - printf("\nparser_example1\n"); - LOG_MSG("parser_example1"); - - - Z3_parse_smtlib_string(ctx, - "(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))", - 0, 0, 0, - 0, 0, 0); - num_formulas = Z3_get_smtlib_num_formulas(ctx); - for (i = 0; i < num_formulas; i++) { - Z3_ast f = Z3_get_smtlib_formula(ctx, i); - printf("formula %d: %s\n", i, Z3_ast_to_string(ctx, f)); - Z3_solver_assert(ctx, s, f); - } - - check(ctx, s, Z3_L_TRUE); - - del_solver(ctx, s); - Z3_del_context(ctx); -} /** \brief Demonstrates how to initialize the parser symbol table. @@ -1690,12 +1660,11 @@ void parser_example2() names[0] = Z3_mk_string_symbol(ctx, "a"); names[1] = Z3_mk_string_symbol(ctx, "b"); - Z3_parse_smtlib_string(ctx, - "(benchmark tst :formula (> a b))", + f = Z3_parse_smtlib2_string(ctx, + "(assert (> a b))", 0, 0, 0, /* 'x' and 'y' declarations are inserted as 'a' and 'b' into the parser symbol table. */ 2, names, decls); - f = Z3_get_smtlib_formula(ctx, 0); printf("formula: %s\n", Z3_ast_to_string(ctx, f)); Z3_solver_assert(ctx, s, f); check(ctx, s, Z3_L_TRUE); @@ -1737,11 +1706,10 @@ void parser_example3() assert_comm_axiom(ctx, s, g); - Z3_parse_smtlib_string(ctx, - "(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (g x 0) (g 0 y)))))", + thm = Z3_parse_smtlib2_string(ctx, + "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (g x 0) (g 0 y)))))", 0, 0, 0, 1, &g_name, &g); - thm = Z3_get_smtlib_formula(ctx, 0); printf("formula: %s\n", Z3_ast_to_string(ctx, thm)); prove(ctx, s, thm, Z3_TRUE); @@ -1749,41 +1717,6 @@ void parser_example3() Z3_del_context(ctx); } -/** - \brief Display the declarations, assumptions and formulas in a SMT-LIB string. -*/ -void parser_example4() -{ - Z3_context ctx; - unsigned i, num_decls, num_assumptions, num_formulas; - - printf("\nparser_example4\n"); - LOG_MSG("parser_example4"); - - ctx = mk_context(); - - Z3_parse_smtlib_string(ctx, - "(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))", - 0, 0, 0, - 0, 0, 0); - num_decls = Z3_get_smtlib_num_decls(ctx); - for (i = 0; i < num_decls; i++) { - Z3_func_decl d = Z3_get_smtlib_decl(ctx, i); - printf("declaration %d: %s\n", i, Z3_func_decl_to_string(ctx, d)); - } - num_assumptions = Z3_get_smtlib_num_assumptions(ctx); - for (i = 0; i < num_assumptions; i++) { - Z3_ast a = Z3_get_smtlib_assumption(ctx, i); - printf("assumption %d: %s\n", i, Z3_ast_to_string(ctx, a)); - } - num_formulas = Z3_get_smtlib_num_formulas(ctx); - for (i = 0; i < num_formulas; i++) { - Z3_ast f = Z3_get_smtlib_formula(ctx, i); - printf("formula %d: %s\n", i, Z3_ast_to_string(ctx, f)); - } - Z3_del_context(ctx); -} - /** \brief Demonstrates how to handle parser errors using Z3 error handling support. */ @@ -1802,9 +1735,9 @@ void parser_example5() { s = mk_solver(ctx); Z3_del_config(cfg); - Z3_parse_smtlib_string(ctx, + Z3_parse_smtlib2_string(ctx, /* the following string has a parsing error: missing parenthesis */ - "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", + "(declare-const x Int) declare-const y Int) (assert (and (> x y) (> x 0)))", 0, 0, 0, 0, 0, 0); e = Z3_get_error_code(ctx); @@ -1817,7 +1750,7 @@ void parser_example5() { err: printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { - printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); + printf("Error message: '%s'.\n",Z3_get_parser_error(ctx)); del_solver(ctx, s); Z3_del_context(ctx); } @@ -2600,7 +2533,7 @@ void reference_counter_example() { cfg = Z3_mk_config(); Z3_set_param_value(cfg, "model", "true"); - // Create a Z3 context where the user is reponsible for managing + // Create a Z3 context where the user is responsible for managing // Z3_ast reference counters. ctx = Z3_mk_context_rc(cfg); Z3_del_config(cfg); @@ -3065,10 +2998,8 @@ int main() { two_contexts_example1(); error_code_example1(); error_code_example2(); - parser_example1(); parser_example2(); parser_example3(); - parser_example4(); parser_example5(); numeral_example(); ite_example(); diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 64149a553..aec3bdcc5 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -173,10 +173,9 @@ namespace test_mapi throw new Exception("function must be binary, and argument types must be equal to return type"); } - string bench = string.Format("(benchmark comm :formula (forall (x {0}) (y {1}) (= ({2} x y) ({3} y x))))", + string bench = string.Format("(assert (forall ((x {0}) (y {1})) (= ({2} x y) ({3} y x))))", t.Name, t.Name, f.Name, f.Name); - ctx.ParseSMTLIBString(bench, new Symbol[] { t.Name }, new Sort[] { t }, new Symbol[] { f.Name }, new FuncDecl[] { f }); - return ctx.SMTLIBFormulas[0]; + return ctx.ParseSMTLIB2String(bench, new Symbol[] { t.Name }, new Sort[] { t }, new Symbol[] { f.Name }, new FuncDecl[] { f }); } /// @@ -623,7 +622,7 @@ namespace test_mapi Console.WriteLine("{0}", q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.MkBound(1, ctx.IntSort); Expr y = ctx.MkBound(0, ctx.IntSort); @@ -965,21 +964,6 @@ namespace test_mapi } } - /// - /// Shows how to read an SMT1 file. - /// - static void SMT1FileTest(string filename) - { - Console.Write("SMT File test "); - - using (Context ctx = new Context(new Dictionary() { { "MODEL", "true" } })) - { - ctx.ParseSMTLIBFile(filename); - - BoolExpr a = ctx.MkAnd(ctx.SMTLIBFormulas); - Console.WriteLine("read formula: " + a); - } - } /// /// Shows how to read an SMT2 file. @@ -1399,11 +1383,10 @@ namespace test_mapi { Console.WriteLine("ParserExample1"); - ctx.ParseSMTLIBString("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); - foreach (BoolExpr f in ctx.SMTLIBFormulas) - Console.WriteLine("formula {0}", f); + var fml = ctx.ParseSMTLIB2String("(declare-const x Int) (declare-const y Int) (assert (> x y)) (assert (> x 0))"); + Console.WriteLine("formula {0}", fml); - Model m = Check(ctx, ctx.MkAnd(ctx.SMTLIBFormulas), Status.SATISFIABLE); + Model m = Check(ctx, fml, Status.SATISFIABLE); } /// @@ -1412,15 +1395,11 @@ namespace test_mapi public static void ParserExample2(Context ctx) { Console.WriteLine("ParserExample2"); - Symbol[] declNames = { ctx.MkSymbol("a"), ctx.MkSymbol("b") }; FuncDecl a = ctx.MkConstDecl(declNames[0], ctx.MkIntSort()); FuncDecl b = ctx.MkConstDecl(declNames[1], ctx.MkIntSort()); FuncDecl[] decls = new FuncDecl[] { a, b }; - - ctx.ParseSMTLIBString("(benchmark tst :formula (> a b))", - null, null, declNames, decls); - BoolExpr f = ctx.SMTLIBFormulas[0]; + BoolExpr f = ctx.ParseSMTLIB2String("(assert (> a b))", null, null, declNames, decls); Console.WriteLine("formula: {0}", f); Check(ctx, f, Status.SATISFIABLE); } @@ -1438,39 +1417,15 @@ namespace test_mapi BoolExpr ca = CommAxiom(ctx, g); - ctx.ParseSMTLIBString("(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (gg x 0) (gg 0 y)))))", + BoolExpr thm = ctx.ParseSMTLIB2String("(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.MkSymbol("gg") }, new FuncDecl[] { g }); - BoolExpr thm = ctx.SMTLIBFormulas[0]; Console.WriteLine("formula: {0}", thm); Prove(ctx, thm, false, ca); } - /// - /// Display the declarations, assumptions and formulas in a SMT-LIB string. - /// - public static void ParserExample4(Context ctx) - { - Console.WriteLine("ParserExample4"); - - ctx.ParseSMTLIBString - ("(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))"); - foreach (var decl in ctx.SMTLIBDecls) - { - Console.WriteLine("Declaration: {0}", decl); - } - foreach (var f in ctx.SMTLIBAssumptions) - { - Console.WriteLine("Assumption: {0}", f); - } - foreach (var f in ctx.SMTLIBFormulas) - { - Console.WriteLine("Formula: {0}", f); - } - } - /// /// Demonstrates how to handle parser errors using Z3 error handling support. /// @@ -1481,9 +1436,9 @@ namespace test_mapi try { - ctx.ParseSMTLIBString( + ctx.ParseSMTLIB2String( /* the following string has a parsing error: missing parenthesis */ - "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))"); + "(declare-const x Int (declare-const y Int)) (assert (> x y))"); } catch (Z3Exception e) { @@ -1990,7 +1945,7 @@ namespace test_mapi BoolExpr p2 = ctx.MkBoolConst("P2"); BoolExpr p3 = ctx.MkBoolConst("P3"); BoolExpr p4 = ctx.MkBoolConst("P4"); - BoolExpr[] assumptions = new BoolExpr[] { ctx.MkNot(p1), ctx.MkNot(p2), ctx.MkNot(p3), ctx.MkNot(p4) }; + Expr[] assumptions = new Expr[] { ctx.MkNot(p1), ctx.MkNot(p2), ctx.MkNot(p3), ctx.MkNot(p4) }; BoolExpr f1 = ctx.MkAnd(new BoolExpr[] { pa, pb, pc }); BoolExpr f2 = ctx.MkAnd(new BoolExpr[] { pa, ctx.MkNot(pb), pc }); BoolExpr f3 = ctx.MkOr(ctx.MkNot(pa), ctx.MkNot(pc)); @@ -2213,7 +2168,6 @@ namespace test_mapi BitvectorExample2(ctx); ParserExample1(ctx); ParserExample2(ctx); - ParserExample4(ctx); ParserExample5(ctx); ITEExample(ctx); EvalExample1(ctx); diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 25076e27c..7b8902768 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -170,10 +170,9 @@ class JavaExample String bench = "(benchmark comm :formula (forall (x " + t.getName() + ") (y " + t.getName() + ") (= (" + f.getName() + " x y) (" + f.getName() + " y x))))"; - ctx.parseSMTLIBString(bench, new Symbol[] { t.getName() }, + return ctx.parseSMTLIB2String(bench, new Symbol[] { t.getName() }, new Sort[] { t }, new Symbol[] { f.getName() }, new FuncDecl[] { f }); - return ctx.getSMTLIBFormulas()[0]; } // / "Hello world" example: create a Z3 logical context, and delete it. @@ -661,7 +660,7 @@ class JavaExample System.out.println(q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.mkBound(1, ctx.getIntSort()); Expr y = ctx.mkBound(0, ctx.getIntSort()); @@ -1028,21 +1027,6 @@ class JavaExample } } - // / Shows how to read an SMT1 file. - - void smt1FileTest(String filename) - { - System.out.print("SMT File test "); - - { - HashMap cfg = new HashMap(); - Context ctx = new Context(cfg); - ctx.parseSMTLIBFile(filename, null, null, null, null); - - BoolExpr a = ctx.mkAnd(ctx.getSMTLIBFormulas()); - System.out.println("read formula: " + a); - } - } // / Shows how to read an SMT2 file. @@ -1459,15 +1443,13 @@ class JavaExample System.out.println("ParserExample1"); Log.append("ParserExample1"); - ctx.parseSMTLIBString( - "(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))", + BoolExpr f = ctx.parseSMTLIB2String( + "(declare-const x Int) (declare-const y Int) (assert (and (> x y) (> x 0)))", null, null, null, null); - for (BoolExpr f : ctx.getSMTLIBFormulas()) - System.out.println("formula " + f); + System.out.println("formula " + f); @SuppressWarnings("unused") - Model m = check(ctx, ctx.mkAnd(ctx.getSMTLIBFormulas()), - Status.SATISFIABLE); + Model m = check(ctx, f, Status.SATISFIABLE); } // / Demonstrates how to initialize the parser symbol table. @@ -1482,9 +1464,8 @@ class JavaExample FuncDecl b = ctx.mkConstDecl(declNames[1], ctx.mkIntSort()); FuncDecl[] decls = new FuncDecl[] { a, b }; - ctx.parseSMTLIBString("(benchmark tst :formula (> a b))", null, null, + BoolExpr f = ctx.parseSMTLIB2String("(assert (> a b))", null, null, declNames, decls); - BoolExpr f = ctx.getSMTLIBFormulas()[0]; System.out.println("formula: " + f); check(ctx, f, Status.SATISFIABLE); } @@ -1502,39 +1483,14 @@ class JavaExample BoolExpr ca = commAxiom(ctx, g); - ctx.parseSMTLIBString( - "(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (gg x 0) (gg 0 y)))))", + BoolExpr thm = ctx.parseSMTLIB2String( + "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.mkSymbol("gg") }, new FuncDecl[] { g }); - - BoolExpr thm = ctx.getSMTLIBFormulas()[0]; System.out.println("formula: " + thm); prove(ctx, thm, false, ca); } - // / Display the declarations, assumptions and formulas in a SMT-LIB string. - - public void parserExample4(Context ctx) - { - System.out.println("ParserExample4"); - Log.append("ParserExample4"); - - ctx.parseSMTLIBString( - "(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))", - null, null, null, null); - for (FuncDecl decl : ctx.getSMTLIBDecls()) - { - System.out.println("Declaration: " + decl); - } - for (BoolExpr f : ctx.getSMTLIBAssumptions()) - { - System.out.println("Assumption: " + f); - } - for (BoolExpr f : ctx.getSMTLIBFormulas()) - { - System.out.println("Formula: " + f); - } - } // / Demonstrates how to handle parser errors using Z3 error handling // support. @@ -1546,12 +1502,12 @@ class JavaExample try { - ctx.parseSMTLIBString( + ctx.parseSMTLIB2String( /* * the following string has a parsing error: missing * parenthesis */ - "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", + "(declare-const x Int (declare-const y Int)) (assert (> x y))", null, null, null, null); } catch (Z3Exception e) { @@ -2341,7 +2297,6 @@ class JavaExample p.bitvectorExample2(ctx); p.parserExample1(ctx); p.parserExample2(ctx); - p.parserExample4(ctx); p.parserExample5(ctx); p.iteExample(ctx); p.evalExample1(ctx); diff --git a/examples/maxsat/README b/examples/maxsat/README index e5e4ba610..6c24da66b 100644 --- a/examples/maxsat/README +++ b/examples/maxsat/README @@ -9,4 +9,4 @@ On OSX and Linux, you must install z3 first using sudo make install OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (OSX) with the build directory. You need that to be able to find the Z3 shared library. -This directory contains a test file (ex.smt) that can be use as input for the maxsat test application. +This directory contains a test file (ex.smt) that can be used as input for the maxsat test application. diff --git a/examples/maxsat/ex.smt b/examples/maxsat/ex.smt index 14ac0db89..d28b27c80 100644 --- a/examples/maxsat/ex.smt +++ b/examples/maxsat/ex.smt @@ -1,11 +1,11 @@ -(benchmark ex - :logic AUFLIA - :extrafuns ((x Int) (y Int) (z Int)) - :assumption (> x 0) - :assumption (<= x -1) - :assumption (or (> x 0) (< y 1)) - :assumption (> y 2) - :assumption (> y 3) - :assumption (<= y -1) - :formula (= z (+ x y))) +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(assert-soft (> x 0)) +(assert-soft (<= x -1)) +(assert-soft (or (> x 0) (< y 1))) +(assert-soft (> y 2)) +(assert-soft (> y 3)) +(assert-soft (<= y -1)) +(assert (= z (+ x y))) \ No newline at end of file diff --git a/examples/maxsat/maxsat.c b/examples/maxsat/maxsat.c index a312e79ad..5696f5b89 100644 --- a/examples/maxsat/maxsat.c +++ b/examples/maxsat/maxsat.c @@ -116,41 +116,6 @@ Z3_ast mk_binary_and(Z3_context ctx, Z3_ast in_1, Z3_ast in_2) } -/** - \brief Get hard constraints from a SMT-LIB file. We assume hard constraints - are formulas preceeded with the keyword :formula. - Return an array containing all formulas read by the last Z3_parse_smtlib_file invocation. - It will store the number of formulas in num_cnstrs. -*/ -Z3_ast * get_hard_constraints(Z3_context ctx, unsigned * num_cnstrs) -{ - Z3_ast * result; - unsigned i; - *num_cnstrs = Z3_get_smtlib_num_formulas(ctx); - result = (Z3_ast *) malloc(sizeof(Z3_ast) * (*num_cnstrs)); - for (i = 0; i < *num_cnstrs; i++) { - result[i] = Z3_get_smtlib_formula(ctx, i); - } - return result; -} - -/** - \brief Get soft constraints from a SMT-LIB file. We assume soft constraints - are formulas preceeded with the keyword :assumption. - Return an array containing all assumptions read by the last Z3_parse_smtlib_file invocation. - It will store the number of formulas in num_cnstrs. -*/ -Z3_ast * get_soft_constraints(Z3_context ctx, unsigned * num_cnstrs) -{ - Z3_ast * result; - unsigned i; - *num_cnstrs = Z3_get_smtlib_num_assumptions(ctx); - result = (Z3_ast *) malloc(sizeof(Z3_ast) * (*num_cnstrs)); - for (i = 0; i < *num_cnstrs; i++) { - result[i] = Z3_get_smtlib_assumption(ctx, i); - } - return result; -} /** \brief Free the given array of cnstrs that was allocated using get_hard_constraints or get_soft_constraints. @@ -610,14 +575,37 @@ int smtlib_maxsat(char * file_name, int approach) { Z3_context ctx; Z3_solver s; + unsigned i; + Z3_optimize opt; unsigned num_hard_cnstrs, num_soft_cnstrs; Z3_ast * hard_cnstrs, * soft_cnstrs; + Z3_ast_vector hard, objs; + Z3_app soft; unsigned result = 0; ctx = mk_context(); s = mk_solver(ctx); - Z3_parse_smtlib_file(ctx, file_name, 0, 0, 0, 0, 0, 0); - hard_cnstrs = get_hard_constraints(ctx, &num_hard_cnstrs); - soft_cnstrs = get_soft_constraints(ctx, &num_soft_cnstrs); + opt = Z3_mk_optimize(ctx); + Z3_optimize_inc_ref(ctx, opt); + Z3_optimize_from_file(ctx, opt, file_name); + hard = Z3_optimize_get_assertions(ctx, opt); + Z3_ast_vector_inc_ref(ctx, hard); + num_hard_cnstrs = Z3_ast_vector_size(ctx, hard); + hard_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_hard_cnstrs)); + for (i = 0; i < num_hard_cnstrs; i++) { + hard_cnstrs[i] = Z3_ast_vector_get(ctx, hard, i); + } + objs = Z3_optimize_get_objectives(ctx, opt); + Z3_ast_vector_inc_ref(ctx, objs); + + // soft constraints are stored in a single objective which is a sum + // of if-then-else expressions. + soft = Z3_to_app(ctx, Z3_ast_vector_get(ctx, objs, 0)); + num_soft_cnstrs = Z3_get_app_num_args(ctx, soft); + soft_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_soft_cnstrs)); + for (i = 0; i < num_soft_cnstrs; ++i) { + soft_cnstrs[i] = Z3_get_app_arg(ctx, Z3_to_app(ctx, Z3_get_app_arg(ctx, soft, i)), 0); + } + switch (approach) { case NAIVE_MAXSAT: result = naive_maxsat(ctx, s, num_hard_cnstrs, hard_cnstrs, num_soft_cnstrs, soft_cnstrs); @@ -633,6 +621,7 @@ int smtlib_maxsat(char * file_name, int approach) free_cnstr_array(hard_cnstrs); free_cnstr_array(soft_cnstrs); Z3_solver_dec_ref(ctx, s); + Z3_optimize_dec_ref(ctx, opt); return result; } diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 05190f217..8f75e97ed 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 5, 1, 0) + set_version(4, 6, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') @@ -75,10 +75,9 @@ def init_project_def(): add_lib('smtlogic_tactics', ['ackermannization', 'sat_solver', 'arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe','nlsat_smt_tactic'], 'tactic/smtlogics') add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic', 'arith_tactics', 'smtlogic_tactics'], 'tactic/fpa') add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') - add_lib('smtparser', ['portfolio'], 'parsers/smt') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_interp.h', 'z3_fpa.h', 'z3_spacer.h'] - add_lib('api', ['portfolio', 'smtparser', 'realclosure', 'interp', 'opt'], + add_lib('api', ['portfolio', 'realclosure', 'interp', 'opt'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing', 'simplex'], exe_name='test-z3', install=False) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b155fd7c2..03256125c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1990,7 +1990,7 @@ class MLComponent(Component): out.write('%s.cmxa: %s %s %s %s.cma\n' % (z3mls, cmxs, stubso, z3dllso, z3mls)) out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmxs, LIBZ3)) out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls)) - out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) + out.write('\t%s -linkall -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) out.write('\n') out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls)) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfe6e5265..7cde89ae2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,7 +98,6 @@ add_subdirectory(sat/sat_solver) add_subdirectory(tactic/smtlogics) add_subdirectory(tactic/fpa) add_subdirectory(tactic/portfolio) -add_subdirectory(parsers/smt) add_subdirectory(opt) add_subdirectory(api) add_subdirectory(api/dll) diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index a413376ac..fcdbb1651 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -71,5 +71,4 @@ z3_add_component(api opt portfolio realclosure - smtparser ) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index e22603225..ae23ca100 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -832,30 +832,9 @@ extern "C" { case Z3_PRINT_LOW_LEVEL: buffer << mk_ll_pp(to_ast(a), mk_c(c)->m()); break; - case Z3_PRINT_SMTLIB_COMPLIANT: { - ast_smt_pp pp(mk_c(c)->m()); - pp_params params; - pp.set_simplify_implies(params.simplify_implies()); - ast* a1 = to_ast(a); - pp.set_logic(mk_c(c)->fparams().m_logic); - if (!is_expr(a1)) { - buffer << mk_pp(a1, mk_c(c)->m()); - break; - } - if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB_COMPLIANT) { - pp.display_expr(buffer, to_expr(a1)); - break; - } - if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB2_COMPLIANT) { - pp.display_expr_smt2(buffer, to_expr(a1)); - break; - } - break; - } - case Z3_PRINT_SMTLIB2_COMPLIANT: { + case Z3_PRINT_SMTLIB2_COMPLIANT: buffer << mk_ismt2_pp(to_ast(a), mk_c(c)->m()); break; - } default: UNREACHABLE(); } @@ -893,12 +872,7 @@ extern "C" { for (unsigned i = 0; i < num_assumptions; ++i) { pp.add_assumption(to_expr(assumptions[i])); } - if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB2_COMPLIANT) { - pp.display_smt2(buffer, to_expr(formula)); - } - else { - pp.display(buffer, to_expr(formula)); - } + pp.display_smt2(buffer, to_expr(formula)); return mk_c(c)->mk_external_string(buffer.str()); Z3_CATCH_RETURN(""); } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 1e3f7a0a4..23ac62a66 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -19,7 +19,6 @@ Revision History: --*/ #include #include "api/api_context.h" -#include "parsers/smt/smtparser.h" #include "util/version.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" @@ -89,8 +88,6 @@ namespace api { m_print_mode = Z3_PRINT_SMTLIB_FULL; m_searching = false; - m_smtlib_parser = 0; - m_smtlib_parser_has_decls = false; m_interruptable = 0; m_error_handler = &default_error_handler; @@ -111,13 +108,13 @@ namespace api { context::~context() { - reset_parser(); m_last_obj = 0; u_map::iterator it = m_allocated_objects.begin(); while (it != m_allocated_objects.end()) { - DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", it->m_key, typeid(*it->m_value).name());); + api::object* val = it->m_value; + DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", it->m_key, typeid(*val).name());); m_allocated_objects.remove(it->m_key); - dealloc(it->m_value); + dealloc(val); it = m_allocated_objects.begin(); } } @@ -304,39 +301,6 @@ namespace api { } } - - // ------------------------ - // - // Parser interface for backward compatibility - // - // ------------------------ - - void context::reset_parser() { - if (m_smtlib_parser) { - dealloc(m_smtlib_parser); - m_smtlib_parser = 0; - m_smtlib_parser_has_decls = false; - m_smtlib_parser_decls.reset(); - m_smtlib_parser_sorts.reset(); - } - SASSERT(!m_smtlib_parser_has_decls); - } - - void context::extract_smtlib_parser_decls() { - if (m_smtlib_parser) { - if (!m_smtlib_parser_has_decls) { - smtlib::symtable * table = m_smtlib_parser->get_benchmark()->get_symtable(); - table->get_func_decls(m_smtlib_parser_decls); - table->get_sorts(m_smtlib_parser_sorts); - m_smtlib_parser_has_decls = true; - } - } - else { - m_smtlib_parser_decls.reset(); - m_smtlib_parser_sorts.reset(); - } - } - // ------------------------ // // RCF manager diff --git a/src/api/api_context.h b/src/api/api_context.h index 6f8dc43f6..58893d1c1 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -220,19 +220,11 @@ namespace api { // ------------------------ // - // Parser interface for backward compatibility + // Parser interface // // ------------------------ - // TODO: move to a "parser" object visible to the external world. - std::string m_smtlib_error_buffer; - smtlib::parser * m_smtlib_parser; - bool m_smtlib_parser_has_decls; - ptr_vector m_smtlib_parser_decls; - ptr_vector m_smtlib_parser_sorts; - - void reset_parser(); - void extract_smtlib_parser_decls(); + std::string m_parser_error_buffer; }; diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index 416c71adf..d6f4e1128 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -510,31 +510,15 @@ extern "C" { read_error.clear(); try { std::string foo(filename); - if (foo.size() >= 5 && foo.substr(foo.size() - 5) == ".smt2"){ - Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); - Z3_app app = Z3_to_app(ctx, assrts); - int nconjs = Z3_get_app_num_args(ctx, app); - assertions.resize(nconjs); - for (int k = 0; k < nconjs; k++) - assertions[k] = Z3_get_app_arg(ctx, app, k); - } - else { - Z3_parse_smtlib_file(ctx, filename, 0, 0, 0, 0, 0, 0); - int numa = Z3_get_smtlib_num_assumptions(ctx); - int numf = Z3_get_smtlib_num_formulas(ctx); - int num = numa + numf; - - assertions.resize(num); - for (int j = 0; j < num; j++){ - if (j < numa) - assertions[j] = Z3_get_smtlib_assumption(ctx, j); - else - assertions[j] = Z3_get_smtlib_formula(ctx, j - numa); - } - } + Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); + Z3_app app = Z3_to_app(ctx, assrts); + int nconjs = Z3_get_app_num_args(ctx, app); + assertions.resize(nconjs); + for (int k = 0; k < nconjs; k++) + assertions[k] = Z3_get_app_arg(ctx, app, k); } catch (...) { - read_error << "SMTLIB parse error: " << Z3_get_smtlib_error(ctx); + read_error << "SMTLIB parse error: " << Z3_get_parser_error(ctx); read_msg = read_error.str(); *error = read_msg.c_str(); return false; diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index bda33f186..d9936ff66 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -212,6 +212,18 @@ extern "C" { RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } + + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context target) { + Z3_TRY; + LOG_Z3_model_translate(c, m, target); + RESET_ERROR_CODE(); + Z3_model_ref* dst = alloc(Z3_model_ref, *mk_c(target)); + ast_translation tr(mk_c(c)->m(), mk_c(target)->m()); + dst->m_model = to_model_ref(m)->translate(tr); + mk_c(target)->save_object(dst); + RETURN_Z3(of_model(dst)); + Z3_CATCH_RETURN(0); + } Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { Z3_TRY; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 9f5f7dd5d..0d96a6719 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -16,17 +16,19 @@ Revision History: --*/ #include +#include "util/cancel_eh.h" +#include "util/file_path.h" +#include "util/scoped_timer.h" +#include "parsers/smt2/smt2parser.h" +#include "opt/opt_context.h" +#include "opt/opt_cmds.h" +#include "opt/opt_parse.h" #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_stats.h" #include "api/api_context.h" #include "api/api_util.h" #include "api/api_model.h" -#include "opt/opt_context.h" -#include "opt/opt_cmds.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "parsers/smt2/smt2parser.h" #include "api/api_ast_vector.h" extern "C" { @@ -281,16 +283,40 @@ extern "C" { static void Z3_optimize_from_stream( Z3_context c, Z3_optimize opt, - std::istream& s) { - ast_manager& m = mk_c(c)->m(); + std::istream& s, + char const* ext) { + ast_manager& m = mk_c(c)->m(); + if (ext && std::string("opb") == ext) { + unsigned_vector h; + parse_opb(*to_optimize_ptr(opt), s, h); + return; + } + if (ext && std::string("wcnf") == ext) { + unsigned_vector h; + parse_wcnf(*to_optimize_ptr(opt), s, h); + return; + } scoped_ptr ctx = alloc(cmd_context, false, &m); install_opt_cmds(*ctx.get(), to_optimize_ptr(opt)); + std::stringstream errstrm; + ctx->set_regular_stream(errstrm); ctx->set_ignore_check(true); - if (!parse_smt2_commands(*ctx.get(), s)) { + try { + if (!parse_smt2_commands(*ctx.get(), s)) { + mk_c(c)->m_parser_error_buffer = errstrm.str(); + ctx = nullptr; + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + } + catch (z3_exception& e) { + errstrm << e.msg(); + mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return; - } + } + ptr_vector::const_iterator it = ctx->begin_assertions(); ptr_vector::const_iterator end = ctx->end_assertions(); for (; it != end; ++it) { @@ -298,6 +324,8 @@ extern "C" { } } + + void Z3_API Z3_optimize_from_string( Z3_context c, Z3_optimize d, @@ -306,7 +334,7 @@ extern "C" { //LOG_Z3_optimize_from_string(c, d, s); std::string str(s); std::istringstream is(str); - Z3_optimize_from_stream(c, d, is); + Z3_optimize_from_stream(c, d, is, nullptr); Z3_CATCH; } @@ -322,7 +350,7 @@ extern "C" { strm << "Could not open file " << s; throw default_exception(strm.str()); } - Z3_optimize_from_stream(c, d, is); + Z3_optimize_from_stream(c, d, is, get_extension(s)); Z3_CATCH; } @@ -335,8 +363,8 @@ extern "C" { mk_c(c)->save_object(v); expr_ref_vector hard(mk_c(c)->m()); to_optimize_ptr(o)->get_hard_constraints(hard); - for (unsigned i = 0; i < hard.size(); i++) { - v->m_ast_vector.push_back(hard[i].get()); + for (expr* h : hard) { + v->m_ast_vector.push_back(h); } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index b3252281b..d5a98672b 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -22,232 +22,16 @@ Revision History: #include "api/api_util.h" #include "cmd_context/cmd_context.h" #include "parsers/smt2/smt2parser.h" -#include "parsers/smt/smtparser.h" #include "solver/solver_na2as.h" extern "C" { - void init_smtlib_parser(Z3_context c, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const types[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { - mk_c(c)->reset_parser(); - mk_c(c)->m_smtlib_parser = smtlib::parser::create(mk_c(c)->m()); - mk_c(c)->m_smtlib_parser->initialize_smtlib(); - smtlib::symtable * table = mk_c(c)->m_smtlib_parser->get_benchmark()->get_symtable(); - for (unsigned i = 0; i < num_sorts; i++) { - table->insert(to_symbol(sort_names[i]), to_sort(types[i])); - } - for (unsigned i = 0; i < num_decls; i++) { - table->insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); - } - } - - void Z3_API Z3_parse_smtlib_string(Z3_context c, - const char * str, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { - Z3_TRY; - LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - scoped_ptr outs = alloc(std::ostringstream); - bool ok = false; - RESET_ERROR_CODE(); - init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(*outs); - try { - ok = mk_c(c)->m_smtlib_parser->parse_string(str); - } - catch (...) { - ok = false; - } - mk_c(c)->m_smtlib_error_buffer = outs->str(); - outs = nullptr; - if (!ok) { - mk_c(c)->reset_parser(); - SET_ERROR_CODE(Z3_PARSER_ERROR); - } - Z3_CATCH; - } - - void Z3_API Z3_parse_smtlib_file(Z3_context c, - const char * file_name, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const types[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { + Z3_string Z3_API Z3_get_parser_error(Z3_context c) { Z3_TRY; - LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); - bool ok = false; - RESET_ERROR_CODE(); - scoped_ptr outs = alloc(std::ostringstream); - init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(*outs); - try { - ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); - } - catch(...) { - ok = false; - } - mk_c(c)->m_smtlib_error_buffer = outs->str(); - outs = nullptr; - if (!ok) { - mk_c(c)->reset_parser(); - SET_ERROR_CODE(Z3_PARSER_ERROR); - } - Z3_CATCH; - } - - unsigned Z3_API Z3_get_smtlib_num_formulas(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_formulas(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - return mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_formulas(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_ast Z3_API Z3_get_smtlib_formula(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_formula(c, i); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - if (i < mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_formulas()) { - ast * f = mk_c(c)->m_smtlib_parser->get_benchmark()->begin_formulas()[i]; - mk_c(c)->save_ast_trail(f); - RETURN_Z3(of_ast(f)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - unsigned Z3_API Z3_get_smtlib_num_assumptions(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_assumptions(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - return mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_axioms(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_ast Z3_API Z3_get_smtlib_assumption(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_assumption(c, i); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - if (i < mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_axioms()) { - ast * a = mk_c(c)->m_smtlib_parser->get_benchmark()->begin_axioms()[i]; - mk_c(c)->save_ast_trail(a); - RETURN_Z3(of_ast(a)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - unsigned Z3_API Z3_get_smtlib_num_decls(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_decls(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - mk_c(c)->extract_smtlib_parser_decls(); - return mk_c(c)->m_smtlib_parser_decls.size(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_func_decl Z3_API Z3_get_smtlib_decl(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_decl(c, i); + LOG_Z3_get_parser_error(c); RESET_ERROR_CODE(); - mk_c(c)->extract_smtlib_parser_decls(); - if (mk_c(c)->m_smtlib_parser) { - if (i < mk_c(c)->m_smtlib_parser_decls.size()) { - func_decl * d = mk_c(c)->m_smtlib_parser_decls[i]; - mk_c(c)->save_ast_trail(d); - RETURN_Z3(of_func_decl(d)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - unsigned Z3_API Z3_get_smtlib_num_sorts(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_sorts(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - mk_c(c)->extract_smtlib_parser_decls(); - return mk_c(c)->m_smtlib_parser_sorts.size(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_sort Z3_API Z3_get_smtlib_sort(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_sort(c, i); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - mk_c(c)->extract_smtlib_parser_decls(); - if (i < mk_c(c)->m_smtlib_parser_sorts.size()) { - sort* s = mk_c(c)->m_smtlib_parser_sorts[i]; - mk_c(c)->save_ast_trail(s); - RETURN_Z3(of_sort(s)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - Z3_string Z3_API Z3_get_smtlib_error(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_error(c); - RESET_ERROR_CODE(); - return mk_c(c)->m_smtlib_error_buffer.c_str(); + return mk_c(c)->m_parser_error_buffer.c_str(); Z3_CATCH_RETURN(""); } @@ -268,10 +52,26 @@ extern "C" { ctx->insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); } for (unsigned i = 0; i < num_sorts; ++i) { - psort* ps = ctx->pm().mk_psort_cnst(to_sort(sorts[i])); - ctx->insert(ctx->pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps)); + sort* srt = to_sort(sorts[i]); + symbol name(to_symbol(sort_names[i])); + if (!ctx->find_psort_decl(name)) { + psort* ps = ctx->pm().mk_psort_cnst(srt); + ctx->insert(ctx->pm().mk_psort_user_decl(0, name, ps)); + } } - if (!parse_smt2_commands(*ctx.get(), is)) { + std::stringstream errstrm; + ctx->set_regular_stream(errstrm); + try { + if (!parse_smt2_commands(*ctx.get(), is)) { + ctx = nullptr; + mk_c(c)->m_parser_error_buffer = errstrm.str(); + SET_ERROR_CODE(Z3_PARSER_ERROR); + return of_ast(mk_c(c)->m().mk_true()); + } + } + catch (z3_exception& e) { + errstrm << e.msg(); + mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return of_ast(mk_c(c)->m().mk_true()); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 2030c5210..0a0039f4c 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -28,11 +28,17 @@ Revision History: #include "solver/tactic2solver.h" #include "util/scoped_ctrl_c.h" #include "util/cancel_eh.h" +#include "util/file_path.h" #include "util/scoped_timer.h" #include "tactic/portfolio/smt_strategic_solver.h" #include "smt/smt_solver.h" #include "smt/smt_implied_equalities.h" #include "solver/smt_logics.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" +#include "sat/dimacs.h" +#include "sat/sat_solver.h" +#include "sat/tactic/goal2sat.h" extern "C" { @@ -121,6 +127,63 @@ extern "C" { Z3_CATCH_RETURN(0); } + void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) { + scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); + ctx->set_ignore_check(true); + + if (!parse_smt2_commands(*ctx.get(), is)) { + ctx = nullptr; + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + + bool initialized = to_solver(s)->m_solver.get() != 0; + if (!initialized) + init_solver(c, s); + ptr_vector::const_iterator it = ctx->begin_assertions(); + ptr_vector::const_iterator end = ctx->end_assertions(); + for (; it != end; ++it) { + to_solver_ref(s)->assert_expr(*it); + } + // to_solver_ref(s)->set_model_converter(ctx->get_model_converter()); + } + + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string c_str) { + Z3_TRY; + LOG_Z3_solver_from_string(c, s, c_str); + std::string str(c_str); + std::istringstream is(str); + solver_from_stream(c, s, is); + Z3_CATCH; + } + + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name) { + Z3_TRY; + LOG_Z3_solver_from_file(c, s, file_name); + char const* ext = get_extension(file_name); + std::ifstream is(file_name); + if (!is) { + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + } + else if (ext && std::string("dimacs") == ext) { + ast_manager& m = to_solver_ref(s)->get_manager(); + sat::solver solver(to_solver_ref(s)->get_params(), m.limit(), nullptr); + parse_dimacs(is, solver); + sat2goal s2g; + model_converter_ref mc; + atom2bool_var a2b(m); + goal g(m); + s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); + for (unsigned i = 0; i < g.size(); ++i) { + to_solver_ref(s)->assert_expr(g.form(i)); + } + } + else { + solver_from_stream(c, s, is); + } + Z3_CATCH; + } + Z3_string Z3_API Z3_solver_get_help(Z3_context c, Z3_solver s) { Z3_TRY; LOG_Z3_solver_get_help(c, s); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4b5e9d04e..b1e667e9f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -174,6 +174,15 @@ namespace z3 { return e; } + void check_parser_error() const { + Z3_error_code e = Z3_get_error_code(*this); + if (e != Z3_OK && enable_exceptions()) { + Z3_string s = Z3_get_parser_error(*this); + if (s && *s) Z3_THROW(exception(s)); + } + check_error(); + } + /** \brief The C++ API uses by defaults exceptions on errors. For applications that don't work well with exceptions (there should be only few) @@ -1527,6 +1536,38 @@ namespace z3 { m_vector = s.m_vector; return *this; } + /* + Disabled pending C++98 build upgrade + bool contains(T const& x) const { + for (T y : *this) if (eq(x, y)) return true; + return false; + } + */ + + class iterator { + ast_vector_tpl const* m_vector; + unsigned m_index; + public: + iterator(ast_vector_tpl const* v, unsigned i): m_vector(v), m_index(i) {} + iterator(iterator& other): m_vector(other.m_vector), m_index(other.m_index) {} + iterator operator=(iterator const& other) { m_vector = other.m_vector; m_index = other.m_index; return *this; } + + bool operator==(iterator const& other) { + return other.m_index == m_index; + }; + bool operator!=(iterator const& other) { + return other.m_index != m_index; + }; + iterator& operator++() { + ++m_index; + return *this; + } + iterator operator++(int) { iterator tmp = *this; ++m_index; return tmp; } + T * operator->() const { return &(operator*()); } + T operator*() const { return (*m_vector)[m_index]; } + }; + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, size()); } friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } }; @@ -1768,9 +1809,11 @@ namespace z3 { Z3_model_inc_ref(ctx(), m); } public: + struct translate {}; model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } 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() { Z3_model_dec_ref(ctx(), m_model); } operator Z3_model() const { return m_model; } model & operator=(model const & s) { @@ -1902,6 +1945,11 @@ namespace z3 { return *this; } void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } + void set(char const * k, bool v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, unsigned v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, double v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, symbol const & v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, char const* v) { params p(ctx()); p.set(k, v); set(p); } void push() { Z3_solver_push(ctx(), m_solver); check_error(); } void pop(unsigned n = 1) { Z3_solver_pop(ctx(), m_solver, n); check_error(); } void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } @@ -1914,6 +1962,11 @@ namespace z3 { void add(expr const & e, char const * p) { add(e, ctx().bool_const(p)); } + // fails for some compilers: + // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } + void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } + check_result check() { Z3_lbool r = Z3_solver_check(ctx(), m_solver); check_error(); return to_check_result(r); } check_result check(unsigned n, expr * const assumptions) { array _assumptions(n); @@ -1994,6 +2047,8 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } + // fails for some compilers: + // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } @@ -2774,13 +2829,12 @@ namespace z3 { inline expr context::parse_string(char const* s) { Z3_ast r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); - check_error(); - return expr(*this, r); - + check_parser_error(); + return expr(*this, r); } inline expr context::parse_file(char const* s) { Z3_ast r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); - check_error(); + check_parser_error(); return expr(*this, r); } @@ -2796,7 +2850,7 @@ namespace z3 { decl_names[i] = decls[i].name(); } Z3_ast r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); - check_error(); + check_parser_error(); return expr(*this, r); } @@ -2812,7 +2866,7 @@ namespace z3 { decl_names[i] = decls[i].name(); } Z3_ast r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); - check_error(); + check_parser_error(); return expr(*this, r); } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 914cee615..cbd6a1bac 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2262,7 +2262,7 @@ namespace Microsoft.Z3 /// Maps f on the argument arrays. /// /// - /// Eeach element of args must be of an array sort [domain_i -> range_i]. + /// Each element of args must be of an array sort [domain_i -> range_i]. /// The function declaration f must have type range_1 .. range_n -> range. /// v must have sort range. The sort of the result is [domain_i -> range]. /// @@ -2862,7 +2862,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2878,7 +2878,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2894,7 +2894,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2910,7 +2910,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -3211,7 +3211,7 @@ namespace Microsoft.Z3 /// Create an existential Quantifier. /// /// - /// Creates an existential quantifier using de-Brujin indexed variables. + /// Creates an existential quantifier using de-Bruijn indexed variables. /// (). /// public Quantifier MkExists(Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) @@ -3320,160 +3320,10 @@ namespace Microsoft.Z3 #endregion #region SMT Files & Strings - /// - /// Convert a benchmark into an SMT-LIB formatted string. - /// - /// Name of the benchmark. The argument is optional. - /// The benchmark logic. - /// The status string (sat, unsat, or unknown) - /// Other attributes, such as source, difficulty or category. - /// Auxiliary assumptions. - /// Formula to be checked for consistency in conjunction with assumptions. - /// A string representation of the benchmark. - public string BenchmarkToSMTString(string name, string logic, string status, string attributes, - BoolExpr[] assumptions, BoolExpr formula) - { - Contract.Requires(assumptions != null); - Contract.Requires(formula != null); - Contract.Ensures(Contract.Result() != null); - - return Native.Z3_benchmark_to_smtlib_string(nCtx, name, logic, status, attributes, - (uint)assumptions.Length, AST.ArrayToNative(assumptions), - formula.NativeObject); - } - - /// - /// Parse the given string using the SMT-LIB parser. - /// - /// - /// The symbol table of the parser can be initialized using the given sorts and declarations. - /// The symbols in the arrays and - /// don't need to match the names of the sorts and declarations in the arrays - /// and . This is a useful feature since we can use arbitrary names to - /// reference sorts and declarations. - /// - public void ParseSMTLIBString(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) - { - uint csn = Symbol.ArrayLength(sortNames); - uint cs = Sort.ArrayLength(sorts); - uint cdn = Symbol.ArrayLength(declNames); - uint cd = AST.ArrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.Z3_parse_smtlib_string(nCtx, str, - AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), - AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)); - } - - /// - /// Parse the given file using the SMT-LIB parser. - /// - /// - public void ParseSMTLIBFile(string fileName, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) - { - uint csn = Symbol.ArrayLength(sortNames); - uint cs = Sort.ArrayLength(sorts); - uint cdn = Symbol.ArrayLength(declNames); - uint cd = AST.ArrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.Z3_parse_smtlib_file(nCtx, fileName, - AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), - AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)); - } - - /// - /// The number of SMTLIB formulas parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBFormulas { get { return Native.Z3_get_smtlib_num_formulas(nCtx); } } - - /// - /// The formulas parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public BoolExpr[] SMTLIBFormulas - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBFormulas; - BoolExpr[] res = new BoolExpr[n]; - for (uint i = 0; i < n; i++) - res[i] = (BoolExpr)Expr.Create(this, Native.Z3_get_smtlib_formula(nCtx, i)); - return res; - } - } - - /// - /// The number of SMTLIB assumptions parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBAssumptions { get { return Native.Z3_get_smtlib_num_assumptions(nCtx); } } - - /// - /// The assumptions parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public BoolExpr[] SMTLIBAssumptions - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBAssumptions; - BoolExpr[] res = new BoolExpr[n]; - for (uint i = 0; i < n; i++) - res[i] = (BoolExpr)Expr.Create(this, Native.Z3_get_smtlib_assumption(nCtx, i)); - return res; - } - } - - /// - /// The number of SMTLIB declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBDecls { get { return Native.Z3_get_smtlib_num_decls(nCtx); } } - - /// - /// The declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public FuncDecl[] SMTLIBDecls - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBDecls; - FuncDecl[] res = new FuncDecl[n]; - for (uint i = 0; i < n; i++) - res[i] = new FuncDecl(this, Native.Z3_get_smtlib_decl(nCtx, i)); - return res; - } - } - - /// - /// The number of SMTLIB sorts parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBSorts { get { return Native.Z3_get_smtlib_num_sorts(nCtx); } } - - /// - /// The declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public Sort[] SMTLIBSorts - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBSorts; - Sort[] res = new Sort[n]; - for (uint i = 0; i < n; i++) - res[i] = Sort.Create(this, Native.Z3_get_smtlib_sort(nCtx, i)); - return res; - } - } /// /// Parse the given string using the SMT-LIB2 parser. /// - /// /// A conjunction of assertions in the scope (up to push/pop) at the end of the string. public BoolExpr ParseSMTLIB2String(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) { diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 4fd306052..0726f9d53 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -959,7 +959,7 @@ namespace Microsoft.Z3 /// Tn: (R t_n s_n) /// [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) /// Remark: if t_i == s_i, then the antecedent Ti is suppressed. - /// That is, reflexivity proofs are supressed to save space. + /// That is, reflexivity proofs are suppressed to save space. /// public bool IsProofMonotonicity { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MONOTONICITY; } } @@ -1002,7 +1002,7 @@ namespace Microsoft.Z3 public bool IsProofAndElimination { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_AND_ELIM; } } /// - /// Indicates whether the term is a proof by eliminiation of not-or + /// Indicates whether the term is a proof by elimination of not-or /// /// /// Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). @@ -1112,7 +1112,7 @@ namespace Microsoft.Z3 public bool IsProofQuantInst { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_QUANT_INST; } } /// - /// Indicates whether the term is a hypthesis marker. + /// Indicates whether the term is a hypothesis marker. /// /// Mark a hypothesis in a natural deduction style proof. public bool IsProofHypothesis { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_HYPOTHESIS; } } @@ -1433,7 +1433,7 @@ namespace Microsoft.Z3 /// /// Filter (restrict) a relation with respect to a predicate. /// The first argument is a relation. - /// The second argument is a predicate with free de-Brujin indices + /// The second argument is a predicate with free de-Bruijn indices /// corresponding to the columns of the relation. /// So the first column in the relation has index 0. /// @@ -1649,7 +1649,7 @@ namespace Microsoft.Z3 public bool IsFPMul { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MUL; } } /// - /// Indicates whether the term is a floating-point divison term + /// Indicates whether the term is a floating-point division term /// public bool IsFPDiv { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_DIV; } } @@ -1709,7 +1709,7 @@ namespace Microsoft.Z3 public bool IsFPLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_LE; } } /// - /// Indicates whether the term is a floating-point greater-than or erqual term + /// Indicates whether the term is a floating-point greater-than or equal term /// public bool IsFPGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_GE; } } @@ -1789,7 +1789,7 @@ namespace Microsoft.Z3 #region Bound Variables /// - /// The de-Burijn index of a bound variable. + /// The de-Bruijn index of a bound variable. /// /// /// Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index 12992fa8a..d11a57052 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -253,7 +253,7 @@ namespace Microsoft.Z3 /// The uninterpreted sorts that the model has an interpretation for. /// /// - /// Z3 also provides an intepretation for uninterpreted sorts used in a formula. + /// Z3 also provides an interpretation for uninterpreted sorts used in a formula. /// The interpretation for a sort is a finite set of distinct values. We say this finite set is /// the "universe" of the sort. /// diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index 23b037c78..37d73d5b1 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -31,98 +31,108 @@ namespace Microsoft.Z3 /// /// Adds a parameter setting. /// - public void Add(Symbol name, bool value) + public Params Add(Symbol name, bool value) { Contract.Requires(name != null); Native.Z3_params_set_bool(Context.nCtx, NativeObject, name.NativeObject, (value) ? 1 : 0); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, uint value) + public Params Add(Symbol name, uint value) { Contract.Requires(name != null); Native.Z3_params_set_uint(Context.nCtx, NativeObject, name.NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, double value) + public Params Add(Symbol name, double value) { - Contract.Requires(name != null); - + Contract.Requires(name != null); + Native.Z3_params_set_double(Context.nCtx, NativeObject, name.NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, string value) + public Params Add(Symbol name, string value) { Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, Context.MkSymbol(value).NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, Symbol value) + public Params Add(Symbol name, Symbol value) { Contract.Requires(name != null); Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, bool value) + public Params Add(string name, bool value) { Native.Z3_params_set_bool(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, (value) ? 1 : 0); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, uint value) + public Params Add(string name, uint value) { Native.Z3_params_set_uint(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, double value) + public Params Add(string name, double value) { Native.Z3_params_set_double(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, Symbol value) + public Params Add(string name, Symbol value) { Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value.NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, string value) + public Params Add(string name, string value) { Contract.Requires(name != null); Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, Context.MkSymbol(value).NativeObject); + return this; } /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index dff2677df..a176e790b 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -57,6 +57,49 @@ namespace Microsoft.Z3 } } + /// + /// Sets parameter on the solver + /// + public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + + + /// /// Retrieves parameter descriptions for solver. /// @@ -140,11 +183,11 @@ namespace Microsoft.Z3 /// using the Boolean constants in ps. /// /// - /// This API is an alternative to with assumptions for extracting unsat cores. + /// This API is an alternative to with assumptions for extracting unsat cores. /// Both APIs can be used in the same solver. The unsat core will contain a combination /// of the Boolean variables provided using /// and the Boolean literals - /// provided using with assumptions. + /// provided using with assumptions. /// public void AssertAndTrack(BoolExpr[] constraints, BoolExpr[] ps) { @@ -165,11 +208,11 @@ namespace Microsoft.Z3 /// using the Boolean constant p. /// /// - /// This API is an alternative to with assumptions for extracting unsat cores. + /// This API is an alternative to with assumptions for extracting unsat cores. /// Both APIs can be used in the same solver. The unsat core will contain a combination /// of the Boolean variables provided using /// and the Boolean literals - /// provided using with assumptions. + /// provided using with assumptions. /// public void AssertAndTrack(BoolExpr constraint, BoolExpr p) { @@ -181,6 +224,22 @@ namespace Microsoft.Z3 Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraint.NativeObject, p.NativeObject); } + /// + /// Load solver assertions from a file. + /// + public void FromFile(string file) + { + Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); + } + + /// + /// Load solver assertions from a string. + /// + public void FromString(string str) + { + Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); + } + /// /// The number of assertions in the solver. /// @@ -225,6 +284,25 @@ namespace Microsoft.Z3 return lboolToStatus(r); } + /// + /// Checks whether the assertions in the solver are consistent or not. + /// + /// + /// + /// + /// + /// + public Status Check(IEnumerable assumptions) + { + Z3_lbool r; + BoolExpr[] asms = assumptions.ToArray(); + if (asms.Length == 0) + r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + else + r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)asms.Length, AST.ArrayToNative(asms)); + return lboolToStatus(r); + } + /// /// Retrieve fixed assignments to the set of variables in the form of consequences. /// Each consequence is an implication of the form diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 76303d670..7e73fc15e 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2234,7 +2234,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2250,7 +2250,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2438,7 +2438,7 @@ public class Context implements AutoCloseable { } /** - * Creates an existential quantifier using de-Brujin indexed variables. + * Creates an existential quantifier using de-Bruijn indexed variables. * @see #mkForall(Sort[],Symbol[],Expr,int,Pattern[],Expr[],Symbol,Symbol) **/ public Quantifier mkExists(Sort[] sorts, Symbol[] names, Expr body, @@ -2540,147 +2540,8 @@ public class Context implements AutoCloseable { AST.arrayToNative(assumptions), formula.getNativeObject()); } - /** - * Parse the given string using the SMT-LIB parser. - * Remarks: The symbol - * table of the parser can be initialized using the given sorts and - * declarations. The symbols in the arrays {@code sortNames} and - * {@code declNames} don't need to match the names of the sorts - * and declarations in the arrays {@code sorts} and {@code decls}. This is a useful feature since we can use arbitrary names - * to reference sorts and declarations. - **/ - public void parseSMTLIBString(String str, Symbol[] sortNames, Sort[] sorts, - Symbol[] declNames, FuncDecl[] decls) - { - int csn = Symbol.arrayLength(sortNames); - int cs = Sort.arrayLength(sorts); - int cdn = Symbol.arrayLength(declNames); - int cd = AST.arrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.parseSmtlibString(nCtx(), str, AST.arrayLength(sorts), - Symbol.arrayToNative(sortNames), AST.arrayToNative(sorts), - AST.arrayLength(decls), Symbol.arrayToNative(declNames), - AST.arrayToNative(decls)); - } - - /** - * Parse the given file using the SMT-LIB parser. - * @see #parseSMTLIBString - **/ - public void parseSMTLIBFile(String fileName, Symbol[] sortNames, - Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) - - { - int csn = Symbol.arrayLength(sortNames); - int cs = Sort.arrayLength(sorts); - int cdn = Symbol.arrayLength(declNames); - int cd = AST.arrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.parseSmtlibFile(nCtx(), fileName, AST.arrayLength(sorts), - Symbol.arrayToNative(sortNames), AST.arrayToNative(sorts), - AST.arrayLength(decls), Symbol.arrayToNative(declNames), - AST.arrayToNative(decls)); - } - - /** - * The number of SMTLIB formulas parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBFormulas() - { - return Native.getSmtlibNumFormulas(nCtx()); - } - - /** - * The formulas parsed by the last call to {@code ParseSMTLIBString} or - * {@code ParseSMTLIBFile}. - **/ - public BoolExpr[] getSMTLIBFormulas() - { - - int n = getNumSMTLIBFormulas(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = (BoolExpr) Expr.create(this, - Native.getSmtlibFormula(nCtx(), i)); - return res; - } - - /** - * The number of SMTLIB assumptions parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBAssumptions() - { - return Native.getSmtlibNumAssumptions(nCtx()); - } - - /** - * The assumptions parsed by the last call to {@code ParseSMTLIBString} - * or {@code ParseSMTLIBFile}. - **/ - public BoolExpr[] getSMTLIBAssumptions() - { - - int n = getNumSMTLIBAssumptions(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = (BoolExpr) Expr.create(this, - Native.getSmtlibAssumption(nCtx(), i)); - return res; - } - - /** - * The number of SMTLIB declarations parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBDecls() - { - return Native.getSmtlibNumDecls(nCtx()); - } - - /** - * The declarations parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public FuncDecl[] getSMTLIBDecls() - { - - int n = getNumSMTLIBDecls(); - FuncDecl[] res = new FuncDecl[n]; - for (int i = 0; i < n; i++) - res[i] = new FuncDecl(this, Native.getSmtlibDecl(nCtx(), i)); - return res; - } - - /** - * The number of SMTLIB sorts parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBSorts() - { - return Native.getSmtlibNumSorts(nCtx()); - } - - /** - * The declarations parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public Sort[] getSMTLIBSorts() - { - - int n = getNumSMTLIBSorts(); - Sort[] res = new Sort[n]; - for (int i = 0; i < n; i++) - res[i] = Sort.create(this, Native.getSmtlibSort(nCtx(), i)); - return res; - } - /** * Parse the given string using the SMT-LIB2 parser. - * @see #parseSMTLIBString * * @return A conjunction of assertions in the scope (up to push/pop) at the * end of the string. diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index d3793a24b..7b20b7993 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1421,7 +1421,7 @@ public class Expr extends AST * Remarks: T1: * (R t_1 s_1) ... Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... * t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is - * suppressed. That is, reflexivity proofs are supressed to save space. + * suppressed. That is, reflexivity proofs are suppressed to save space. * * @throws Z3Exception on error * @return a boolean @@ -1473,7 +1473,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a proof by eliminiation of not-or + * Indicates whether the term is a proof by elimination of not-or * Remarks: * Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). * T1: (not (or l_1 ... l_n)) [not-or-elim T1]: (not l_i) * @throws Z3Exception on error * @return a boolean @@ -1605,7 +1605,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a hypthesis marker. + * Indicates whether the term is a hypothesis marker. * Remarks: Mark a * hypothesis in a natural deduction style proof. * @throws Z3Exception on error @@ -1987,7 +1987,7 @@ public class Expr extends AST * Indicates whether the term is a relation filter * Remarks: Filter * (restrict) a relation with respect to a predicate. The first argument is - * a relation. The second argument is a predicate with free de-Brujin + * a relation. The second argument is a predicate with free de-Bruijn * indices corresponding to the columns of the relation. So the first column * in the relation has index 0. * @throws Z3Exception on error @@ -2094,7 +2094,7 @@ public class Expr extends AST } /** - * The de-Burijn index of a bound variable. + * The de-Bruijn index of a bound variable. * Remarks: Bound variables are * indexed by de-Bruijn indices. It is perhaps easiest to explain the * meaning of de-Bruijn indices by indicating the compilation process from diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 9c7013aca..d809b6790 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -239,7 +239,7 @@ public class Model extends Z3Object { /** * The uninterpreted sorts that the model has an interpretation for. - * Remarks: Z3 also provides an intepretation for uninterpreted sorts used + * Remarks: Z3 also provides an interpretation for uninterpreted sorts used * in a formula. The interpretation for a sort is a finite set of distinct * values. We say this finite set is the "universe" of the sort. * diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 19f3b01da..5bd4e65ba 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -1,3 +1,4 @@ + /** Copyright (c) 2012-2014 Microsoft Corporation @@ -120,6 +121,23 @@ public class Solver extends Z3Object { } } + /** + * Load solver assertions from a file. + */ + public void fromFile(String file) + { + Native.solverFromFile(getContext().nCtx(), getNativeObject(), file); + } + + /** + * Load solver assertions from a string. + */ + public void fromString(String str) + { + Native.solverFromString(getContext().nCtx(), getNativeObject(), str); + } + + /** * Assert multiple constraints into the solver, and track them (in the * unsat) core diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 46fe5bd6d..120b0ddfd 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1975,56 +1975,6 @@ struct (List.length assumptions) assumptions formula - let parse_smtlib_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = - let csn = List.length sort_names in - let cs = List.length sorts in - let cdn = List.length decl_names in - let cd = List.length decls in - if (csn <> cs || cdn <> cd) then - raise (Error "Argument size mismatch") - else - Z3native.parse_smtlib_string ctx str - cs sort_names sorts cd decl_names decls - - let parse_smtlib_file (ctx:context) (file_name:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = - let csn = (List.length sort_names) in - let cs = (List.length sorts) in - let cdn = (List.length decl_names) in - let cd = (List.length decls) in - if (csn <> cs || cdn <> cd) then - raise (Error "Argument size mismatch") - else - Z3native.parse_smtlib_file ctx file_name - cs sort_names sorts cd decl_names decls - - let get_num_smtlib_formulas (ctx:context) = Z3native.get_smtlib_num_formulas ctx - - let get_smtlib_formulas (ctx:context) = - let n = get_num_smtlib_formulas ctx in - let f i = Z3native.get_smtlib_formula ctx i in - mk_list f n - - let get_num_smtlib_assumptions (ctx:context) = Z3native.get_smtlib_num_assumptions ctx - - let get_smtlib_assumptions (ctx:context) = - let n = get_num_smtlib_assumptions ctx in - let f i = Z3native.get_smtlib_assumption ctx i in - mk_list f n - - let get_num_smtlib_decls (ctx:context) = Z3native.get_smtlib_num_decls ctx - - let get_smtlib_decls (ctx:context) = - let n = get_num_smtlib_decls ctx in - let f i = Z3native.get_smtlib_decl ctx i in - mk_list f n - - let get_num_smtlib_sorts (ctx:context) = Z3native.get_smtlib_num_sorts ctx - - let get_smtlib_sorts (ctx:context) = - let n = get_num_smtlib_sorts ctx in - let f i = Z3native.get_smtlib_sort ctx i in - mk_list f n - let parse_smtlib2_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = let csn = List.length sort_names in let cs = List.length sorts in @@ -2044,7 +1994,7 @@ struct if csn <> cs || cdn <> cd then raise (Error "Argument size mismatch") else - Z3native.parse_smtlib2_string ctx file_name + Z3native.parse_smtlib2_file ctx file_name cs sort_names sorts cd decl_names decls end diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 4f10b275a..20a1e9c10 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -536,7 +536,7 @@ sig @return A Term with the given value and sort *) val mk_numeral_string : context -> string -> Sort.sort -> expr - (** Create a numeral of a given sort. This function can be use to create numerals that fit in a machine integer. + (** Create a numeral of a given sort. This function can be used to create numerals that fit in a machine integer. It is slightly faster than [MakeNumeral] since it is not necessary to parse a string. @return A Term with the given value and sort *) val mk_numeral_int : context -> int -> Sort.sort -> expr @@ -667,7 +667,7 @@ sig end - (** The de-Burijn index of a bound variable. + (** The de-Bruijn index of a bound variable. Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain the meaning of de-Bruijn indices by indicating the compilation process from @@ -830,7 +830,7 @@ sig (** Maps f on the argument arrays. - Eeach element of [args] must be of an array sort [[domain_i -> range_i]]. + Each element of [args] must be of an array sort [[domain_i -> range_i]]. The function declaration [f] must have type [ range_1 .. range_n -> range]. [v] must have sort range. The sort of the result is [[domain_i -> range]]. {!Z3Array.mk_sort} @@ -962,7 +962,7 @@ sig Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. *) val is_filter : Expr.expr -> bool @@ -2085,7 +2085,7 @@ sig (** Indicates whether an expression is a floating-point lt expression *) val is_lt : Expr.expr -> bool - (** Indicates whether an expression is a floating-point geqexpression *) + (** Indicates whether an expression is a floating-point geq expression *) val is_geq : Expr.expr -> bool (** Indicates whether an expression is a floating-point gt expression *) @@ -2233,7 +2233,7 @@ sig (** Conversion of a 2's complement unsigned bit-vector term into a term of FloatingPoint sort. *) val mk_to_fp_unsigned : context -> Expr.expr -> Expr.expr -> Sort.sort -> Expr.expr - (** C1onversion of a floating-point term into an unsigned bit-vector. *) + (** Conversion of a floating-point term into an unsigned bit-vector. *) val mk_to_ubv : context -> Expr.expr -> Expr.expr -> int -> Expr.expr (** Conversion of a floating-point term into a signed bit-vector. *) @@ -2385,7 +2385,7 @@ sig Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. *) + That is, reflexivity proofs are suppressed to save space. *) val is_monotonicity : Expr.expr -> bool (** Indicates whether the term is a quant-intro proof @@ -2417,7 +2417,7 @@ sig [and-elim T1]: l_i *) val is_and_elimination : Expr.expr -> bool - (** Indicates whether the term is a proof by eliminiation of not-or + (** Indicates whether the term is a proof by elimination of not-or Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). T1: (not (or l_1 ... l_n)) @@ -2500,7 +2500,7 @@ sig A proof of (or (not (forall (x) (P x))) (P a)) *) val is_quant_inst : Expr.expr -> bool - (** Indicates whether the term is a hypthesis marker. + (** Indicates whether the term is a hypothesis marker. Mark a hypothesis in a natural deduction style proof. *) val is_hypothesis : Expr.expr -> bool @@ -2882,7 +2882,7 @@ sig (** The uninterpreted sorts that the model has an interpretation for. - Z3 also provides an intepretation for uninterpreted sorts used in a formula. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort is a finite set of distinct values. We say this finite set is the "universe" of the sort. {!get_num_sorts} @@ -3056,7 +3056,7 @@ sig (** Create a tactic that fails if the probe evaluates to false. *) val fail_if : context -> Probe.probe -> tactic - (** Create a tactic that fails if the goal is not triviall satisfiable (i.e., empty) + (** Create a tactic that fails if the goal is not trivially satisfiable (i.e., empty) or trivially unsatisfiable (i.e., contains `false'). *) val fail_if_not_decided : context -> tactic @@ -3105,7 +3105,7 @@ sig (** True if the entry is float-valued. *) val is_float : statistics_entry -> bool - (** The string representation of the the entry's value. *) + (** The string representation of the entry's value. *) val to_string_value : statistics_entry -> string (** The string representation of the entry (key and value) *) @@ -3370,7 +3370,7 @@ sig (** Assert a constraints into the optimize solver. *) val add : optimize -> Expr.expr list -> unit - (** Asssert a soft constraint. + (** Assert a soft constraint. Supply integer weight and string that identifies a group of soft constraints. *) val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle @@ -3441,51 +3441,12 @@ sig @return A string representation of the benchmark. *) val benchmark_to_smtstring : context -> string -> string -> string -> string -> Expr.expr list -> Expr.expr -> string - (** Parse the given string using the SMT-LIB parser. - - The symbol table of the parser can be initialized using the given sorts and declarations. - The symbols in the arrays in the third and fifth argument - don't need to match the names of the sorts and declarations in the arrays in the fourth - and sixth argument. This is a useful feature since we can use arbitrary names to - reference sorts and declarations. *) - val parse_smtlib_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> unit - - (** Parse the given file using the SMT-LIB parser. - {!parse_smtlib_string} *) - val parse_smtlib_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> unit - - (** The number of SMTLIB formulas parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_formulas : context -> int - - (** The formulas parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_formulas : context -> Expr.expr list - - (** The number of SMTLIB assumptions parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_assumptions : context -> int - - (** The assumptions parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_assumptions : context -> Expr.expr list - - (** The number of SMTLIB declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_decls : context -> int - - (** The declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_decls : context -> FuncDecl.func_decl list - - (** The number of SMTLIB sorts parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_sorts : context -> int - - (** The sort declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_sorts : context -> Sort.sort list - (** Parse the given string using the SMT-LIB2 parser. - {!parse_smtlib_string} @return A conjunction of assertions in the scope (up to push/pop) at the end of the string. *) val parse_smtlib2_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr - (** Parse the given file using the SMT-LIB2 parser. - {!parse_smtlib2_string} *) + (** Parse the given file using the SMT-LIB2 parser. *) val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr end diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1f050d3bd..4896a475d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -182,7 +182,7 @@ class Context: """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions. This method can be invoked from a thread different from the one executing the - interruptable procedure. + interruptible procedure. """ Z3_interrupt(self.ref()) @@ -365,6 +365,12 @@ class AstRef(Z3PPObject): _z3_assert(isinstance(target, Context), "argument must be a Z3 context") return _to_ast_ref(Z3_translate(self.ctx.ref(), self.as_ast(), target.ref()), target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def hash(self): """Return a hashcode for the `self`. @@ -596,7 +602,7 @@ def _sort(ctx, a): return _to_sort_ref(Z3_get_sort(ctx.ref(), a), ctx) def DeclareSort(name, ctx=None): - """Create a new uninterpred sort named `name`. + """Create a new uninterpreted sort named `name`. If `ctx=None`, then the new sort is declared in the global Z3Py context. @@ -718,7 +724,7 @@ class FuncDeclRef(AstRef): The arguments must be Z3 expressions. This method assumes that the sorts of the elements in `args` match the sorts of the - domain. Limited coersion is supported. For example, if + domain. Limited coercion is supported. For example, if args[0] is a Python integer, and the function expects a Z3 integer, then the argument is automatically converted into a Z3 integer. @@ -3568,6 +3574,14 @@ def BV2Int(a, is_signed=False): ## investigate problem with bv2int return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx) +def Int2BV(a, num_bits): + """Return the z3 expression Int2BV(a, num_bits). + It is a bit-vector of width num_bits and represents the + modulo of a by 2^num_bits + """ + ctx = a.ctx + return BitVecRef(Z3_mk_int2bv(ctx.ref(), num_bits, a.as_ast()), ctx) + def BitVecSort(sz, ctx=None): """Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used. @@ -5040,6 +5054,12 @@ class Goal(Z3PPObject): _z3_assert(isinstance(target, Context), "target must be a context") return Goal(goal=Z3_goal_translate(self.ctx.ref(), self.goal, target.ref()), ctx=target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def simplify(self, *arguments, **keywords): """Return a new simplified goal. @@ -5132,9 +5152,18 @@ class AstVector(Z3PPObject): >>> A[1] y """ - if i >= self.__len__(): - raise IndexError - return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + if isinstance(i, int): + if i < 0: + i += self.__len__() + + if i >= self.__len__(): + raise IndexError + return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + elif isinstance(i, slice): + return [_to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, ii), self.ctx) for ii in range(*i.indices(self.__len__()))] + def __setitem__(self, i, v): """Update AST at position `i`. @@ -5213,6 +5242,12 @@ class AstVector(Z3PPObject): """ return AstVector(Z3_ast_vector_translate(self.ctx.ref(), self.vector, other_ctx.ref()), other_ctx) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def __repr__(self): return obj_to_string(self) @@ -5550,6 +5585,17 @@ class FuncInterp(Z3PPObject): raise IndexError return FuncEntry(Z3_func_interp_get_entry(self.ctx.ref(), self.f, idx), self.ctx) + def translate(self, other_ctx): + """Copy model 'self' to context 'other_ctx'. + """ + return ModelRef(Z3_model_translate(self.ctx.ref(), self.model, other_ctx.ref()), other_ctx) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def as_list(self): """Return the function interpretation as a Python list. >>> f = Function('f', IntSort(), IntSort()) @@ -5579,9 +5625,6 @@ class ModelRef(Z3PPObject): self.ctx = ctx Z3_model_inc_ref(self.ctx.ref(), self.model) - def __deepcopy__(self, memo={}): - return ModelRef(self.m, self.ctx) - def __del__(self): if self.ctx.ref() is not None: Z3_model_dec_ref(self.ctx.ref(), self.model) @@ -5835,6 +5878,20 @@ class ModelRef(Z3PPObject): r.append(FuncDeclRef(Z3_model_get_func_decl(self.ctx.ref(), self.model, i), self.ctx)) return r + def translate(self, target): + """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. + """ + if __debug__: + _z3_assert(isinstance(target, Context), "argument must be a Z3 context") + model = Z3_model_translate(self.ctx.ref(), self.model, target.ref()) + return Model(model, target) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def is_as_array(n): """Return true if n is a Z3 expression of the form (_ as-array f).""" return isinstance(n, ExprRef) and Z3_is_as_array(n.ctx.ref(), n.as_ast()) @@ -6037,9 +6094,6 @@ class Solver(Z3PPObject): self.solver = solver Z3_solver_inc_ref(self.ctx.ref(), self.solver) - def __deepcopy__(self, memo={}): - return Solver(self.solver, self.ctx) - def __del__(self): if self.solver is not None and self.ctx.ref() is not None: Z3_solver_dec_ref(self.ctx.ref(), self.solver) @@ -6324,6 +6378,20 @@ class Solver(Z3PPObject): sz = len(consequences) consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences + + def from_file(self, filename): + """Parse assertions from a file""" + try: + Z3_solver_from_file(self.ctx.ref(), self.solver, filename) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) + + def from_string(self, s): + """Parse assertions from a string""" + try: + Z3_solver_from_string(self.ctx.ref(), self.solver, s) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" @@ -6399,6 +6467,12 @@ class Solver(Z3PPObject): solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref()) return Solver(solver, target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def sexpr(self): """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. @@ -6668,11 +6742,17 @@ class Fixedpoint(Z3PPObject): def parse_string(self, s): """Parse rules and queries from a string""" - return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx) + try: + return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def parse_file(self, f): """Parse rules and queries from a file""" - return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx) + try: + return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def get_rules(self): """retrieve rules that have been added to fixedpoint context""" @@ -6995,15 +7075,21 @@ class Optimize(Z3PPObject): def upper_values(self, obj): if not isinstance(obj, OptimizeObjective): raise Z3Exception("Expecting objective handle returned by maximize/minimize") - return obj.upper_values() + return obj.upper_values() def from_file(self, filename): """Parse assertions and objectives from a file""" - Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename) + try: + Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def from_string(self, s): """Parse assertions and objectives from a string""" - Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) + try: + Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def assertions(self): """Return an AST vector containing all added constraints.""" @@ -8071,6 +8157,12 @@ def _dict2darray(decls, ctx): i = i + 1 return sz, _names, _decls +def _handle_parse_error(ex, ctx): + msg = Z3_get_parser_error(ctx.ref()) + if msg != "": + raise Z3Exception(msg) + raise ex + def parse_smt2_string(s, sorts={}, decls={}, ctx=None): """Parse a string in SMT 2.0 format using the given sorts and decls. @@ -8089,7 +8181,10 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - return _to_expr_ref(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + try: + return _to_expr_ref(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + except Z3Exception as e: + _handle_parse_error(e, ctx) def parse_smt2_file(f, sorts={}, decls={}, ctx=None): """Parse a file in SMT 2.0 format using the given sorts and decls. @@ -8099,7 +8194,10 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + try: + return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + except Z3Exception as e: + _handle_parse_error(e, ctx) def Interpolant(a,ctx=None): """Create an interpolation operator. @@ -9145,7 +9243,7 @@ def fpMul(rm, a, b, ctx=None): return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx) def fpDiv(rm, a, b, ctx=None): - """Create a Z3 floating-point divison expression. + """Create a Z3 floating-point division expression. >>> s = FPSort(8, 24) >>> rm = RNE() @@ -9172,7 +9270,7 @@ def fpRem(a, b, ctx=None): return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx) def fpMin(a, b, ctx=None): - """Create a Z3 floating-point minimium expression. + """Create a Z3 floating-point minimum expression. >>> s = FPSort(8, 24) >>> rm = RNE() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index cf1c8fca7..5e5b84450 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -270,7 +270,7 @@ typedef enum - Z3_OP_ARRAY_MAP Array map operator. It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. - - Z3_OP_SET_UNION Set union between two Booelan arrays (two arrays whose range type is Boolean). The function is binary. + - Z3_OP_SET_UNION Set union between two Boolean arrays (two arrays whose range type is Boolean). The function is binary. - Z3_OP_SET_INTERSECT Set intersection between two Boolean arrays. The function is binary. @@ -406,7 +406,7 @@ typedef enum - Z3_OP_BSMUL_NO_UDFL: check that bit-wise signed multiplication does not underflow. Signed multiplication underflows if the operands have opposite signs and the result of multiplication - does not fit within the avaialble bits. Z3_mk_bvmul_no_underflow. + does not fit within the available bits. Z3_mk_bvmul_no_underflow. - Z3_OP_BSDIV_I: Binary signed division. It has the same semantics as Z3_OP_BSDIV, but created in a context where the second operand can be assumed to be non-zero. @@ -485,7 +485,7 @@ typedef enum [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) } Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. + That is, reflexivity proofs are suppressed to save space. - Z3_OP_PR_QUANT_INTRO: Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)). @@ -832,7 +832,7 @@ typedef enum - Z3_OP_RA_FILTER: Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. @@ -969,7 +969,7 @@ typedef enum - Z3_OP_FPA_TO_FP: Floating-point conversion (various) - - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigend bit-vector + - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigned bit-vector - Z3_OP_FPA_TO_UBV: Floating-point conversion to unsigned bit-vector @@ -984,7 +984,7 @@ typedef enum of non-relevant terms in theory_fpa) - Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a - floating-point rouding-mode term + floating-point rounding-mode term The conversion uses the following values: 0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, @@ -1314,13 +1314,11 @@ typedef enum { - Z3_PRINT_SMTLIB_FULL: Print AST nodes in SMTLIB verbose format. - Z3_PRINT_LOW_LEVEL: Print AST nodes using a low-level format. - - Z3_PRINT_SMTLIB_COMPLIANT: Print AST nodes in SMTLIB 1.x compliant format. - Z3_PRINT_SMTLIB2_COMPLIANT: Print AST nodes in SMTLIB 2.x compliant format. */ typedef enum { Z3_PRINT_SMTLIB_FULL, Z3_PRINT_LOW_LEVEL, - Z3_PRINT_SMTLIB_COMPLIANT, Z3_PRINT_SMTLIB2_COMPLIANT } Z3_ast_print_mode; @@ -1333,7 +1331,7 @@ typedef enum { - Z3_IOB: Index out of bounds. - Z3_INVALID_ARG: Invalid argument was provided. - Z3_PARSER_ERROR: An error occurred when parsing a string or file. - - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. + - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib2_string or #Z3_parse_smtlib2_file. - Z3_INVALID_PATTERN: Invalid pattern was used to build a quantifier. - Z3_MEMOUT_FAIL: A memory allocation failure was encountered. - Z3_FILE_ACCESS_ERRROR: A file could not be accessed. @@ -1924,7 +1922,7 @@ extern "C" { \param c logical context \param name name of the enumeration sort. - \param n number of elemenets in enumeration sort. + \param n number of elements in enumeration sort. \param enum_names names of the enumerated elements. \param enum_consts constants corresponding to the enumerated elements. \param enum_testers predicates testing if terms of the enumeration sort correspond to an enumeration. @@ -3188,7 +3186,7 @@ extern "C" { \param c logical context. \param num numerator of rational. - \param den denomerator of rational. + \param den denominator of rational. \pre den != 0 @@ -3203,7 +3201,7 @@ extern "C" { /** \brief Create a numeral of an int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine integer. + This function can be used to create numerals that fit in a machine integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3215,7 +3213,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine unsinged integer. + This function can be used to create numerals that fit in a machine unsigned integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3227,7 +3225,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __int64 integer. + This function can be used to create numerals that fit in a machine __int64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3239,7 +3237,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __uint64 integer. + This function can be used to create numerals that fit in a machine __uint64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3495,8 +3493,8 @@ extern "C" { Z3_ast Z3_API Z3_mk_re_range(Z3_context c, Z3_ast lo, Z3_ast hi); /** - \brief Create a regular expression loop. The supplied regular expression \c r is repated - between \c lo and \c hi times. The \c lo should be below \c hi with one exection: when + \brief Create a regular expression loop. The supplied regular expression \c r is repeated + between \c lo and \c hi times. The \c lo should be below \c hi with one exception: when supplying the value \c hi as 0, the meaning is to repeat the argument \c r at least \c lo number of times, and with an unbounded upper bound. @@ -4250,7 +4248,7 @@ extern "C" { Z3_sort Z3_API Z3_get_decl_sort_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_AST @@ -4259,7 +4257,7 @@ extern "C" { Z3_ast Z3_API Z3_get_decl_ast_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_FUNC_DECL @@ -4301,7 +4299,7 @@ extern "C" { /** \brief Return the i-th argument of the given application. - \pre i < Z3_get_num_args(c, a) + \pre i < Z3_get_app_num_args(c, a) def_API('Z3_get_app_arg', AST, (_in(CONTEXT), _in(APP), _in(UINT))) */ @@ -4329,7 +4327,7 @@ extern "C" { /** \brief Return a hash code for the given AST. - The hash code is structural. You can use Z3_get_ast_id interchangably with + The hash code is structural. You can use Z3_get_ast_id interchangeably with this function. def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST))) @@ -4558,7 +4556,7 @@ extern "C" { Z3_ast Z3_API Z3_get_pattern(Z3_context c, Z3_pattern p, unsigned idx); /** - \brief Return index of de-Brujin bound variable. + \brief Return index of de-Bruijn bound variable. \pre Z3_get_ast_kind(a) == Z3_VAR_AST @@ -4661,7 +4659,7 @@ extern "C" { Provides an interface to the AST simplifier used by Z3. It returns an AST object which is equal to the argument. - The returned AST is simplified using algebraic simplificaiton rules, + The returned AST is simplified using algebraic simplification rules, such as constant propagation (propagating true/false over logical connectives). def_API('Z3_simplify', AST, (_in(CONTEXT), _in(AST))) @@ -4863,9 +4861,9 @@ extern "C" { Z3_func_decl Z3_API Z3_model_get_func_decl(Z3_context c, Z3_model m, unsigned i); /** - \brief Return the number of uninterpreted sorts that \c m assigs an interpretation to. + \brief Return the number of uninterpreted sorts that \c m assigns an interpretation to. - Z3 also provides an intepretation for uninterpreted sorts used in a formua. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort \c s is a finite set of distinct values. We say this finite set is the "universe" of \c s. @@ -4898,6 +4896,13 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_model_get_sort_universe(Z3_context c, Z3_model m, Z3_sort s); + /** + \brief translate model from context c to context \c dst. + + def_API('Z3_model_translate', MODEL, (_in(CONTEXT), _in(MODEL), _in(CONTEXT))) + */ + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context dst); + /** \brief The \ccode{(_ as-array f)} AST node is a construct for assigning interpretations for arrays in Z3. It is the array such that forall indices \c i we have that \ccode{(select (_ as-array f) i)} is equal to \ccode{(f i)}. @@ -4966,7 +4971,7 @@ extern "C" { unsigned Z3_API Z3_func_interp_get_num_entries(Z3_context c, Z3_func_interp f); /** - \brief Return a "point" of the given function intepretation. It represents the + \brief Return a "point" of the given function interpretation. It represents the value of \c f in a particular point. \pre i < Z3_func_interp_get_num_entries(c, f) @@ -5008,7 +5013,7 @@ extern "C" { \brief add a function entry to a function interpretation. \param c logical context - \param fi a function interpregation to be updated. + \param fi a function interpretation to be updated. \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. \param value value of the function when the parameters match args. @@ -5116,7 +5121,7 @@ extern "C" { To print shared common subexpressions only once, use the Z3_PRINT_LOW_LEVEL mode. To print in way that conforms to SMT-LIB standards and uses let - expressions to share common sub-expressions use Z3_PRINT_SMTLIB_COMPLIANT. + expressions to share common sub-expressions use Z3_PRINT_SMTLIB2_COMPLIANT. \sa Z3_ast_to_string \sa Z3_pattern_to_string @@ -5228,115 +5233,13 @@ extern "C" { Z3_symbol const decl_names[], Z3_func_decl const decls[]); - /** - \brief Parse the given string using the SMT-LIB parser. - - The symbol table of the parser can be initialized using the given sorts and declarations. - The symbols in the arrays \c sort_names and \c decl_names don't need to match the names - of the sorts and declarations in the arrays \c sorts and \c decls. This is an useful feature - since we can use arbitrary names to reference sorts and declarations defined using the C API. - - The formulas, assumptions and declarations defined in \c str can be extracted using the functions: - #Z3_get_smtlib_num_formulas, #Z3_get_smtlib_formula, #Z3_get_smtlib_num_assumptions, #Z3_get_smtlib_assumption, - #Z3_get_smtlib_num_decls, and #Z3_get_smtlib_decl. - - def_API('Z3_parse_smtlib_string', VOID, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) - */ - void Z3_API Z3_parse_smtlib_string(Z3_context c, - Z3_string str, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[] - ); - - /** - \brief Similar to #Z3_parse_smtlib_string, but reads the benchmark from a file. - - def_API('Z3_parse_smtlib_file', VOID, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) - */ - void Z3_API Z3_parse_smtlib_file(Z3_context c, - Z3_string file_name, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[] - ); - - /** - \brief Return the number of SMTLIB formulas parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_formulas', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_formulas(Z3_context c); - - /** - \brief Return the i-th formula parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_formulas(c) - - def_API('Z3_get_smtlib_formula', AST, (_in(CONTEXT), _in(UINT))) - */ - Z3_ast Z3_API Z3_get_smtlib_formula(Z3_context c, unsigned i); - - /** - \brief Return the number of SMTLIB assumptions parsed by #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_assumptions', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_assumptions(Z3_context c); - - /** - \brief Return the i-th assumption parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_assumptions(c) - - def_API('Z3_get_smtlib_assumption', AST, (_in(CONTEXT), _in(UINT))) - */ - Z3_ast Z3_API Z3_get_smtlib_assumption(Z3_context c, unsigned i); - - /** - \brief Return the number of declarations parsed by #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_decls', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_decls(Z3_context c); - - /** - \brief Return the i-th declaration parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_decls(c) - - def_API('Z3_get_smtlib_decl', FUNC_DECL, (_in(CONTEXT), _in(UINT))) - */ - Z3_func_decl Z3_API Z3_get_smtlib_decl(Z3_context c, unsigned i); - - /** - \brief Return the number of sorts parsed by #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_sorts', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_sorts(Z3_context c); - - /** - \brief Return the i-th sort parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_sorts(c) - - def_API('Z3_get_smtlib_sort', SORT, (_in(CONTEXT), _in(UINT))) - */ - Z3_sort Z3_API Z3_get_smtlib_sort(Z3_context c, unsigned i); /** \brief Retrieve that last error message information generated from parsing. - def_API('Z3_get_smtlib_error', STRING, (_in(CONTEXT), )) + def_API('Z3_get_parser_error', STRING, (_in(CONTEXT), )) */ - Z3_string Z3_API Z3_get_smtlib_error(Z3_context c); + Z3_string Z3_API Z3_get_parser_error(Z3_context c); /*@}*/ /** @name Error Handling */ @@ -5563,7 +5466,7 @@ extern "C" { Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g); /** - \brief Copy a goal \c g from the context \c source to a the context \c target. + \brief Copy a goal \c g from the context \c source to the context \c target. def_API('Z3_goal_translate', GOAL, (_in(CONTEXT), _in(GOAL), _in(CONTEXT))) */ @@ -6029,7 +5932,7 @@ extern "C" { Z3_solver Z3_API Z3_mk_solver_from_tactic(Z3_context c, Z3_tactic t); /** - \brief Copy a solver \c s from the context \c source to a the context \c target. + \brief Copy a solver \c s from the context \c source to the context \c target. def_API('Z3_solver_translate', SOLVER, (_in(CONTEXT), _in(SOLVER), _in(CONTEXT))) */ @@ -6142,6 +6045,20 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s); + /** + \brief load solver assertions from a file. + + def_API('Z3_solver_from_file', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) + */ + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name); + + /** + \brief load solver assertions from a string. + + def_API('Z3_solver_from_string', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) + */ + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string file_name); + /** \brief Check whether the assertions in a given solver are consistent or not. diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 4b24ea5e6..4850b52a8 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -370,7 +370,7 @@ public: app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); } - app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } + app * mk_add(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_ADD, num_args, args); } app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } @@ -378,7 +378,7 @@ public: app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } - app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } + app * mk_mul(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_MUL, num_args, args); } app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index e7d808b2b..cc4beb1b6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1289,7 +1289,7 @@ decl_kind user_sort_plugin::register_name(symbol s) { decl_plugin * user_sort_plugin::mk_fresh() { user_sort_plugin * p = alloc(user_sort_plugin); - for (symbol const& s : m_sort_names) + for (symbol const& s : m_sort_names) p->register_name(s); return p; } @@ -1415,7 +1415,7 @@ ast_manager::~ast_manager() { p->finalize(); } for (decl_plugin* p : m_plugins) { - if (p) + if (p) dealloc(p); } m_plugins.reset(); @@ -1454,13 +1454,13 @@ ast_manager::~ast_manager() { mark_array_ref(mark, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns()); mark_array_ref(mark, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns()); break; - } - } + } + } for (ast * n : m_ast_table) { if (!mark.is_marked(n)) { roots.push_back(n); } - } + } SASSERT(!roots.empty()); for (unsigned i = 0; i < roots.size(); ++i) { ast* a = roots[i]; @@ -1492,11 +1492,8 @@ void ast_manager::compact_memory() { unsigned capacity = m_ast_table.capacity(); if (capacity > 4*m_ast_table.size()) { ast_table new_ast_table; - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - new_ast_table.insert(*it); - } + for (ast* curr : m_ast_table) + new_ast_table.insert(curr); m_ast_table.swap(new_ast_table); IF_VERBOSE(10, verbose_stream() << "(ast-table :prev-capacity " << capacity << " :capacity " << m_ast_table.capacity() << " :size " << m_ast_table.size() << ")\n";); @@ -1510,10 +1507,7 @@ void ast_manager::compress_ids() { ptr_vector asts; m_expr_id_gen.cleanup(); m_decl_id_gen.cleanup(c_first_decl_id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * n = *it; + for (ast * n : m_ast_table) { if (is_decl(n)) n->m_id = m_decl_id_gen.mk(); else @@ -1521,10 +1515,8 @@ void ast_manager::compress_ids() { asts.push_back(n); } m_ast_table.finalize(); - ptr_vector::iterator it2 = asts.begin(); - ptr_vector::iterator end2 = asts.end(); - for (; it2 != end2; ++it2) - m_ast_table.insert(*it2); + for (ast* a : asts) + m_ast_table.insert(a); } void ast_manager::raise_exception(char const * msg) { @@ -1570,20 +1562,15 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { } void ast_manager::set_next_expr_id(unsigned id) { - while (true) { - id = m_expr_id_gen.set_next_id(id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * curr = *it; - if (curr->get_id() == id) - break; + try_again: + id = m_expr_id_gen.set_next_id(id); + for (ast * curr : m_ast_table) { + if (curr->get_id() == id) { + // id is in use, move to the next one. + ++id; + goto try_again; } - if (it == end) - return; - // id is in use, move to the next one. - id++; - } + } } unsigned ast_manager::get_node_size(ast const * n) { return ::get_node_size(n); } @@ -1683,7 +1670,7 @@ ast * ast_manager::register_node_core(ast * n) { bool contains = m_ast_table.contains(n); CASSERT("nondet_bug", contains || slow_not_contains(n)); #endif - + ast * r = m_ast_table.insert_if_not_there(n); SASSERT(r->m_hash == h); if (r != n) { @@ -2358,8 +2345,9 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * unsigned num_patterns, expr * const * patterns, unsigned num_no_patterns, expr * const * no_patterns) { SASSERT(body); - SASSERT(num_patterns == 0 || num_no_patterns == 0); SASSERT(num_decls > 0); + if (num_patterns != 0 && num_no_patterns != 0) + throw ast_exception("simultaneous patterns and no-patterns not supported"); DEBUG_CODE({ for (unsigned i = 0; i < num_patterns; ++i) { TRACE("ast", tout << i << " " << mk_pp(patterns[i], *this) << "\n";); @@ -2763,7 +2751,7 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) { - if (num_proofs == 0) + if (num_proofs == 0) return nullptr; if (num_proofs == 1) return proofs[0]; diff --git a/src/ast/ast.h b/src/ast/ast.h index 2d06d03de..7a662a193 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef _MSC_VER +# define Z3_NORETURN __declspec(noreturn) +#else +# define Z3_NORETURN [[noreturn]] +#endif + class ast; class ast_manager; @@ -330,7 +336,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss); // ----------------------------------- /** - \brief Extra information that may be attached to intepreted sorts. + \brief Extra information that may be attached to interpreted sorts. */ class sort_info : public decl_info { sort_size m_num_elements; @@ -932,7 +938,7 @@ struct builtin_name { }; /** - \brief Each family of intepreted function declarations and sorts must provide a plugin + \brief Each family of interpreted function declarations and sorts must provide a plugin to build sorts and decls of the family. */ class decl_plugin { @@ -1059,7 +1065,7 @@ protected: ptr_vector m_eq_decls; // cached eqs ptr_vector m_ite_decls; // cached ites - ptr_vector m_oeq_decls; // cached obsevational eqs + ptr_vector m_oeq_decls; // cached observational eqs sort * m_proof_sort; func_decl * m_undef_decl; func_decl * m_true_pr_decl; @@ -1161,7 +1167,7 @@ public: virtual expr * get_some_value(sort * s); }; -typedef app proof; /* a proof is just an applicaton */ +typedef app proof; /* a proof is just an application */ // ----------------------------------- // @@ -1220,7 +1226,7 @@ enum pattern_op_kind { /** \brief Patterns are used to group expressions. These expressions are using during E-matching for - heurisitic quantifier instantiation. + heuristic quantifier instantiation. */ class pattern_decl_plugin : public decl_plugin { public: @@ -1245,13 +1251,13 @@ enum model_value_op_kind { /** \brief Values are used during model construction. All values are assumed to be different. Users should not use them, since they may - introduce unsoundess if the sort of a value is finite. + introduce unsoundness if the sort of a value is finite. Moreover, values should never be internalized in a logical context. However, values can be used during evaluation (i.e., simplification). - \remark Model values can be viewed as the partion ids in Z3 1.x. + \remark Model values can be viewed as the partition ids in Z3 1.x. */ class model_value_decl_plugin : public decl_plugin { public: @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg); + Z3_NORETURN void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 906fd054b..bad4b1984 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -340,8 +340,7 @@ class smt_printer { } - void pp_arg(expr *arg, app *parent) - { + void pp_arg(expr *arg, app *parent) { pp_marked_expr(arg); } @@ -417,7 +416,7 @@ class smt_printer { else if (m_simplify_implies && m_manager.is_implies(decl) && m_manager.is_implies(n->get_arg(1))) { expr *curr = n; expr *arg; - m_out << "(implies (and"; + m_out << "(=> (and"; while (m_manager.is_implies(curr)) { arg = to_app(curr)->get_arg(0); @@ -476,9 +475,8 @@ class smt_printer { } } - void print_no_lets(expr *e) - { - smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, true, m_indent, m_num_var_names, m_var_names); + void print_no_lets(expr *e) { + smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names); p(e); } @@ -511,7 +509,7 @@ class smt_printer { m_out << "(! "; } { - smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names); + smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_simplify_implies, m_indent, m_num_var_names, m_var_names); p(q->get_expr()); } @@ -704,7 +702,7 @@ class smt_printer { public: smt_printer(std::ostream& out, ast_manager& m, ptr_vector& ql, smt_renaming& rn, - symbol logic, bool no_lets, bool is_smt2, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) : + symbol logic, bool no_lets, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) : m_out(out), m_manager(m), m_qlists(ql), @@ -894,25 +892,17 @@ ast_smt_pp::ast_smt_pp(ast_manager& m): m_simplify_implies(true) {} - -void ast_smt_pp::display_expr(std::ostream& strm, expr* n) { - ptr_vector ql; - smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(n); -} - void ast_smt_pp::display_expr_smt2(std::ostream& strm, expr* n, unsigned indent, unsigned num_var_names, char const* const* var_names) { ptr_vector ql; smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, indent, num_var_names, var_names); + smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, indent, num_var_names, var_names); p(n); } void ast_smt_pp::display_ast_smt2(std::ostream& strm, ast* a, unsigned indent, unsigned num_var_names, char const* const* var_names) { ptr_vector ql; smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, indent, num_var_names, var_names); + smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, indent, num_var_names, var_names); if (is_expr(a)) { p(to_expr(a)); } @@ -1021,92 +1011,3 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { p(n); } } - -void ast_smt_pp::display(std::ostream& strm, expr* n) { - ptr_vector ql; - decl_collector decls(m_manager); - smt_renaming rn; - - for (unsigned i = 0; i < m_assumptions.size(); ++i) { - decls.visit(m_assumptions[i].get()); - } - for (unsigned i = 0; i < m_assumptions_star.size(); ++i) { - decls.visit(m_assumptions_star[i].get()); - } - decls.visit(n); - - strm << "(benchmark "; - - if (m_benchmark_name != symbol::null) { - strm << m_benchmark_name << "\n"; - } - else { - strm << "unnamed\n"; - } - if (m_source_info != symbol::null && m_source_info != symbol("")) { - strm << ":source { " << m_source_info << " }\n"; - } - strm << ":status " << m_status << "\n"; - if (m_category != symbol::null && m_category != symbol("")) { - strm << ":category { " << m_category << " }\n"; - } - if (m_logic != symbol::null && m_logic != symbol("")) { - strm << ":logic " << m_logic << "\n"; - } - - if (m_attributes.size() > 0) { - strm << m_attributes.c_str(); - } - - ast_mark sort_mark; - for (unsigned i = 0; i < decls.get_num_sorts(); ++i) { - sort* s = decls.get_sorts()[i]; - if (!(*m_is_declared)(s)) { - smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0); - p.pp_sort_decl(sort_mark, s); - } - } - - for (unsigned i = 0; i < decls.get_num_decls(); ++i) { - func_decl* d = decls.get_func_decls()[i]; - if (!(*m_is_declared)(d)) { - strm << ":extrafuns ("; - smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0); - p(d); - strm << ")\n"; - } - } - - for (unsigned i = 0; i < decls.get_num_preds(); ++i) { - func_decl* d = decls.get_pred_decls()[i]; - if (!(*m_is_declared)(d)) { - strm << ":extrapreds ("; - smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0); - p.visit_pred(d); - strm << ")\n"; - } - } - - for (unsigned i = 0; i < m_assumptions.size(); ++i) { - expr * e = m_assumptions[i].get(); - strm << ":assumption\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(e); - strm << "\n"; - } - - for (unsigned i = 0; i < m_assumptions_star.size(); ++i) { - strm << ":assumption-core\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(m_assumptions_star[i].get()); - strm << "\n"; - } - - { - strm << ":formula\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(n); - strm << "\n"; - } - strm << ")\n"; -} diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index dd2a6d753..ac2e33140 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -75,9 +75,7 @@ public: void set_is_declared(is_declared* id) { m_is_declared = id; } - void display(std::ostream& strm, expr* n); void display_smt2(std::ostream& strm, expr* n); - void display_expr(std::ostream& strm, expr* n); void display_expr_smt2(std::ostream& strm, expr* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); void display_ast_smt2(std::ostream& strm, ast* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 3f9438229..5126198c6 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -502,7 +502,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } case PR_HYPOTHESIS: { - // TBD all branches with hyptheses must be closed by a later lemma. + // TBD all branches with hypotheses must be closed by a later lemma. if (match_proof(p) && match_fact(p, fml)) { return true; @@ -1284,7 +1284,7 @@ void proof_checker::dump_proof(unsigned num_antecedents, expr * const * antecede pp.add_assumption(antecedents[i]); expr_ref n(m); n = m.mk_not(consequent); - pp.display(out, n); + pp.display_smt2(out, n); out.close(); m_proof_lemma_id++; } diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index a80994f6c..cf7e7c951 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -1193,7 +1193,6 @@ bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * return false; } SASSERT(out_bits.empty()); - ptr_buffer na_bits; na_bits.append(sz, a_bits); ptr_buffer nb_bits; diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index 3db4d02a2..9f52ea9a5 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -111,16 +111,6 @@ void static_features::flush_cache() { m_expr2formula_depth.reset(); } -#if 0 -bool static_features::is_non_linear(expr * e) const { - if (!is_arith_expr(e)) - return false; - if (is_numeral(e)) - return true; - if (m_autil.is_add(e)) - return true; // the non -} -#endif bool static_features::is_diff_term(expr const * e, rational & r) const { // lhs can be 'x' or '(+ k x)' @@ -301,10 +291,12 @@ void static_features::update_core(expr * e) { m_num_interpreted_constants++; } if (fid == m_afid) { + // std::cout << mk_pp(e, m_manager) << "\n"; switch (to_app(e)->get_decl_kind()) { case OP_MUL: - if (!is_numeral(to_app(e)->get_arg(0))) + if (!is_numeral(to_app(e)->get_arg(0)) || to_app(e)->get_num_args() > 2) { m_num_non_linear++; + } break; case OP_DIV: case OP_IDIV: diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index a1e7a4745..ec2eea032 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -339,6 +339,13 @@ void ast_object_ref::finalize(cmd_context & ctx) { ctx.m().dec_ref(m_ast); } +void stream_ref::set(std::ostream& out) { + reset(); + m_owner = false; + m_name = "caller-owned"; + m_stream = &out; +} + void stream_ref::set(char const * name) { if (!name) { throw cmd_exception("invalid stream name"); diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index b60f590a9..99d6c8284 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -128,6 +128,7 @@ public: stream_ref(std::string n, std::ostream & d):m_default_name(n), m_default(d), m_name(n), m_stream(&d), m_owner(false) {} ~stream_ref() { reset(); } void set(char const * name); + void set(std::ostream& strm); void reset(); std::ostream & operator*() { return *m_stream; } char const * name() const { return m_name.c_str(); } @@ -404,6 +405,7 @@ public: void reset_object_refs(); void reset_user_tactics(); void set_regular_stream(char const * name) { m_regular.set(name); } + void set_regular_stream(std::ostream& out) { m_regular.set(out); } void set_diagnostic_stream(char const * name); virtual std::ostream & regular_stream() { return *m_regular; } virtual std::ostream & diagnostic_stream() { return *m_diagnostic; } diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7eac1f347..f75fbfa29 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -852,7 +852,7 @@ pdecl_manager::pdecl_manager(ast_manager & m): pdecl_manager::~pdecl_manager() { dec_ref(m_list); reset_sort_info(); - SASSERT(m_sort2psort.empty()); + SASSERT(m_sort2psort.empty()); SASSERT(m_table.empty()); } diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index fc9d0fac6..32cb9cccb 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -55,7 +55,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* The summation rule. The term sum(p,c,i) takes a proof p of an inequality i', an integer coefficient c and an inequality i, and - yieds a proof of i' + ci. */ + yields a proof of i' + ci. */ symb sum; /* Proof rotation. The proof term rotate(q,p) takes a @@ -75,7 +75,7 @@ class iz3proof_itp_impl : public iz3proof_itp { symb leq2eq; /* Equality to inequality. eq2leq(p, q) takes a proof p of x=y, and - a proof q ~(x <= y) and and yields a proof of false. */ + a proof q ~(x <= y) and yields a proof of false. */ symb eq2leq; /* Proof term cong(p,q) takes a proof p of x=y and a proof @@ -97,7 +97,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* This oprerator represents a concatenation of rewrites. The term a=b;c=d represents an A rewrite from a to b, followed by a B - rewrite fron b to c, followed by an A rewrite from c to d. + rewrite from b to c, followed by an A rewrite from c to d. */ symb concat; @@ -1542,7 +1542,7 @@ class iz3proof_itp_impl : public iz3proof_itp { return my_implies(arg(rew,1),arg(rew,2)); } - // make rewrite rew conditon on rewrite cond + // make rewrite rew condition on rewrite cond ast rewrite_conditional(const ast &cond, const ast &rew){ ast cf = rewrite_to_formula(cond); return make(sym(rew),arg(rew,0),my_and(arg(rew,1),cf),arg(rew,2)); diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index b88e488b4..e71475e45 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -9,7 +9,7 @@ Translate a Z3 proof into the interpolating proof calculus. Translation is direct, without transformations on the target proof - representaiton. + representation. Author: diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index d6d392148..51d8489e3 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -150,7 +150,6 @@ namespace polynomial { return r; } - /** \brief Monomials (power products) */ @@ -192,7 +191,7 @@ namespace polynomial { }; static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); } - + monomial(unsigned id, unsigned sz, power const * pws, unsigned h): m_ref_count(0), m_id(id), @@ -257,9 +256,7 @@ namespace polynomial { if (m_size < SMALL_MONOMIAL) { // use linear search for small monomials // search backwards since we usually ask for the degree of "big" variables - unsigned i = last; - while (i > 0) { - --i; + for (unsigned i = last; i-- > 0; ) { if (get_var(i) == x) return i; } @@ -798,9 +795,8 @@ namespace polynomial { dec_ref(m_unit); CTRACE("polynomial", !m_monomials.empty(), tout << "monomials leaked\n"; - monomial_table::iterator it = m_monomials.begin(); monomial_table::iterator end = m_monomials.end(); - for (; it != end; ++it) { - (*it)->display(tout); tout << "\n"; + for (auto * m : m_monomials) { + m->display(tout); tout << "\n"; }); SASSERT(m_monomials.empty()); if (m_own_allocator) @@ -1510,6 +1506,8 @@ namespace polynomial { unsigned id() const { return m_id; } unsigned size() const { return m_size; } monomial * m(unsigned idx) const { SASSERT(idx < size()); return m_ms[idx]; } + monomial *const* begin() const { return m_ms; } + monomial *const* end() const { return m_ms + size(); } numeral const & a(unsigned idx) const { SASSERT(idx < size()); return m_as[idx]; } numeral & a(unsigned idx) { SASSERT(idx < size()); return m_as[idx]; } numeral const * as() const { return m_as; } @@ -1773,11 +1771,9 @@ namespace polynomial { } bool manager::is_linear(polynomial const * p) { - unsigned sz = p->size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_linear(p->m(0))) + for (monomial* m : *p) + if (!is_linear(m)) return false; - } return true; } @@ -2396,6 +2392,7 @@ namespace polynomial { return mm().is_valid(x); } + void add_del_eh(del_eh * eh) { eh->m_next = m_del_eh; m_del_eh = eh; @@ -6101,6 +6098,33 @@ namespace polynomial { }); } + lbool sign(monomial* m, numeral const& c, svector const& sign_of_vars) { + unsigned sz = size(m); + lbool sign1 = m_manager.is_pos(c) ? l_true : l_false; + for (unsigned i = 0; i < sz; ++i) { + var v = get_var(m, i); + unsigned d = degree(m, i); + lbool sign2 = sign_of_vars.get(v, l_undef); + if (sign2 == l_undef) + return l_undef; + else if (1 == (d % 2) && sign2 == l_false) { + sign1 = sign1 == l_true ? l_false : l_true; + } + } + return sign1; + } + + lbool sign(polynomial const * p, svector const& sign_of_vars) { + unsigned sz = size(p); + if (sz == 0) return l_undef; + lbool sign1 = sign(p->m(0), p->a(0), sign_of_vars); + for (unsigned i = 1; sign1 != l_undef && i < sz; ++i) { + if (sign(p->m(i), p->a(i), sign_of_vars) != sign1) + return l_undef; + } + return sign1; + } + bool is_pos(polynomial const * p) { bool found_unit = false; unsigned sz = p->size(); @@ -6372,6 +6396,31 @@ namespace polynomial { R.add(new_a, mk_monomial(new_m)); } return R.mk(); + } + + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + unsigned md = degree(r, x); + if (md == 0) { + result = const_cast(r); + return; + } + result = 0; + polynomial_ref p1(pm()), q1(pm()); + polynomial_ref_buffer ps(pm()); + unsigned sz = r->size(); + for (unsigned i = 0; i < sz; i++) { + monomial * m0 = r->m(i); + unsigned dm = m0->degree_of(x); + SASSERT(md >= dm); + monomial_ref m1(div_x(m0, x), pm()); + pw(p, dm, p1); + pw(q, md - dm, q1); + p1 = mul(r->a(i), m1, p1 * q1); + if (result) + result = add(result, p1); + else + result = p1; + } } @@ -6918,6 +6967,18 @@ namespace polynomial { return m_imp->m().set_zp(p); } + bool manager::is_var(polynomial const* p, var& v) { + return p->size() == 1 && is_var(p->m(0), v) && m_imp->m().is_one(p->a(0)); + } + + bool manager::is_var(monomial const* m, var& v) { + return m->size() == 1 && m->degree(0) == 1 && (v = m->get_var(0), true); + } + + bool manager::is_var_num(polynomial const* p, var& v, scoped_numeral& n) { + return p->size() == 2 && m_imp->m().is_one(p->a(0)) && is_var(p->m(0), v) && is_unit(p->m(1)) && (n = p->a(1), true); + } + small_object_allocator & manager::allocator() const { return m_imp->mm().allocator(); } @@ -7271,6 +7332,10 @@ namespace polynomial { void manager::psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) { m_imp->psc_chain(p, q, x, S); } + + lbool manager::sign(polynomial const * p, svector const& sign_of_vars) { + return m_imp->sign(p, sign_of_vars); + } bool manager::is_pos(polynomial const * p) { return m_imp->is_pos(p); @@ -7307,6 +7372,10 @@ namespace polynomial { polynomial * manager::substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs) { return m_imp->substitute(p, xs_sz, xs, vs); } + + void manager::substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + m_imp->substitute(r, x, p, q, result); + } void manager::factor(polynomial const * p, factors & r, factor_params const & params) { m_imp->factor(p, r, params); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 43b3c1138..b09af94bc 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -29,6 +29,7 @@ Notes: #include "util/params.h" #include "util/mpbqi.h" #include "util/rlimit.h" +#include "util/lbool.h" class small_object_allocator; @@ -98,7 +99,7 @@ namespace polynomial { }; struct display_var_proc { - virtual void operator()(std::ostream & out, var x) const { out << "x" << x; } + virtual std::ostream& operator()(std::ostream & out, var x) const { return out << "x" << x; } }; class polynomial; @@ -306,12 +307,27 @@ namespace polynomial { \brief Return true if m is linear (i.e., it is of the form 1 or x). */ static bool is_linear(monomial const * m); - + /** \brief Return true if all monomials in p are linear. */ static bool is_linear(polynomial const * p); + /** + \brief Return true if the monomial is a variable. + */ + static bool is_var(monomial const* p, var& v); + + /** + \brief Return true if the polynomial is a variable. + */ + bool is_var(polynomial const* p, var& v); + + /** + \brief Return true if the polynomial is of the form x + k + */ + bool is_var_num(polynomial const* p, var& v, scoped_numeral& n); + /** \brief Return the degree of variable x in p. */ @@ -860,7 +876,13 @@ namespace polynomial { \brief Return true if p is a square, and store its square root in r. */ bool sqrt(polynomial const * p, polynomial_ref & r); - + + + /** + \brief obtain the sign of the polynomial given sign of variables. + */ + lbool sign(polynomial const* p, svector const& sign_of_vars); + /** \brief Return true if p is always positive for any assignment of its variables. @@ -936,6 +958,13 @@ namespace polynomial { return substitute(p, 1, &x, &v); } + /** + \brief Apply substiution [x -> p/q] in r. + That is, given r \in Z[x, y_1, .., y_m] return + polynomial q^k * r(p/q, y_1, .., y_m), where k is the maximal degree of x in r. + */ + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result); + /** \brief Factorize the given polynomial p and store its factors in r. */ diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 762e8ceb2..ceec60622 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -634,7 +634,7 @@ namespace simplex { // // max { c*x | A*x = 0 and l <= x <= u } // - // start with feasible assigment + // start with feasible assignment // A*x0 = 0 and l <= x0 <= u // // Identify pivot: i, j: such that x_i is base, diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 9aedf141a..6ac33ae91 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -60,7 +60,7 @@ namespace datalog { ACK_UNBOUND_VAR(var_index) - encodes that the column contains a variable that is unbound (by the corresponding rule body), - var_index is the de-Brujin index (var->get_idx()) + var_index is the de-Bruijn index (var->get_idx()) of the variable associated with the column. ACK_CONSTANT(constant) - encodes that the column contains the constant. diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index c77127eb7..610c523e1 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -609,7 +609,7 @@ namespace datalog { std::string to_nice_string(const relation_element & el) const; /** This one may give a nicer representation of \c el than the - \c to_nice_string(const relation_element & el) function, by unsing the information about the sort + \c to_nice_string(const relation_element & el) function, by using the information about the sort of the element. */ std::string to_nice_string(const relation_sort & s, const relation_element & el) const; diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 898c32449..93dfb0e80 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -44,6 +44,8 @@ namespace nlsat { bool is_learned() const { return m_learned; } literal * begin() { return m_lits; } literal * end() { return m_lits + m_size; } + literal const * begin() const { return m_lits; } + literal const * end() const { return m_lits + m_size; } literal const * c_ptr() const { return m_lits; } void inc_activity() { m_activity++; } void set_activity(unsigned v) { m_activity = v; } diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 2028095f4..090f94eeb 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -672,14 +672,14 @@ namespace nlsat { return new_set; } - void interval_set_manager::peek_in_complement(interval_set const * s, anum & w, bool randomize) { + void interval_set_manager::peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize) { SASSERT(!is_full(s)); if (s == 0) { if (randomize) { int num = m_rand() % 2 == 0 ? 1 : -1; #define MAX_RANDOM_DEN_K 4 int den_k = (m_rand() % MAX_RANDOM_DEN_K); - int den = 1 << den_k; + int den = is_int ? 1 : (1 << den_k); scoped_mpq _w(m_am.qm()); m_am.qm().set(_w, num, den); m_am.set(w, _w); diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index 24b2ab37f..363d48de9 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -108,7 +108,7 @@ namespace nlsat { \pre !is_full(s) */ - void peek_in_complement(interval_set const * s, anum & w, bool randomize); + void peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize); }; typedef obj_ref interval_set_ref; diff --git a/src/nlsat/nlsat_params.pyg b/src/nlsat/nlsat_params.pyg index 6b1577113..0f2e03069 100644 --- a/src/nlsat/nlsat_params.pyg +++ b/src/nlsat/nlsat_params.pyg @@ -10,6 +10,7 @@ def_module_params('nlsat', ('randomize', BOOL, True, "randomize selection of a witness in nlsat."), ('max_conflicts', UINT, UINT_MAX, "maximum number of conflicts."), ('shuffle_vars', BOOL, False, "use a random variable order."), + ('inline_vars', BOOL, False, "inline variables that can be isolated from equations"), ('seed', UINT, 0, "random seed."), ('factor', BOOL, True, "factor polynomials produced during conflict resolution.") )) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index c5e9babae..12b063759 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -18,19 +18,20 @@ Author: Revision History: --*/ +#include "util/z3_exception.h" +#include "util/chashtable.h" +#include "util/id_gen.h" +#include "util/map.h" +#include "util/dependency.h" +#include "util/permutation.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial_cache.h" #include "nlsat/nlsat_solver.h" #include "nlsat/nlsat_clause.h" #include "nlsat/nlsat_assignment.h" #include "nlsat/nlsat_justification.h" #include "nlsat/nlsat_evaluator.h" #include "nlsat/nlsat_explain.h" -#include "math/polynomial/algebraic_numbers.h" -#include "util/z3_exception.h" -#include "util/chashtable.h" -#include "util/id_gen.h" -#include "util/dependency.h" -#include "math/polynomial/polynomial_cache.h" -#include "util/permutation.h" #include "nlsat/nlsat_params.hpp" #define NLSAT_EXTRA_VERBOSE @@ -68,6 +69,7 @@ namespace nlsat { reslimit& m_rlimit; small_object_allocator m_allocator; + bool m_incremental; unsynch_mpq_manager m_qm; pmanager m_pm; cache m_cache; @@ -78,6 +80,8 @@ namespace nlsat { interval_set_manager & m_ism; ineq_atom_table m_ineq_atoms; root_atom_table m_root_atoms; + svector m_patch_var; + polynomial_ref_vector m_patch_num, m_patch_denom; id_gen m_cid_gen; clause_vector m_clauses; // set of clauses @@ -85,7 +89,7 @@ namespace nlsat { unsigned m_num_bool_vars; atom_vector m_atoms; // bool_var -> atom - svector m_bvalues; // boolean assigment + svector m_bvalues; // boolean assignment unsigned_vector m_levels; // bool_var -> level svector m_justifications; vector m_bwatches; // bool_var (that are not attached to atoms) -> clauses where it is maximal @@ -108,11 +112,12 @@ namespace nlsat { m_perm(perm), m_proc(0) { } - virtual void operator()(std::ostream & out, var x) const { + std::ostream& operator()(std::ostream & out, var x) const { if (m_proc == 0) m_default_display_var(out, x); else (*m_proc)(out, m_perm[x]); + return out; } }; perm_display_var_proc m_display_var; @@ -149,6 +154,7 @@ namespace nlsat { bool m_randomize; bool m_random_order; unsigned m_random_seed; + bool m_inline_vars; unsigned m_max_conflicts; // statistics @@ -158,9 +164,10 @@ namespace nlsat { unsigned m_stages; unsigned m_irrational_assignments; // number of irrational witnesses - imp(solver& s, reslimit& rlim, params_ref const & p): + imp(solver& s, reslimit& rlim, params_ref const & p, bool incremental): m_rlimit(rlim), m_allocator("nlsat"), + m_incremental(incremental), m_pm(rlim, m_qm, &m_allocator), m_cache(m_pm), m_am(rlim, m_qm, p, &m_allocator), @@ -168,6 +175,8 @@ namespace nlsat { m_assignment(m_am), m_evaluator(s, m_assignment, m_pm, m_allocator), m_ism(m_evaluator.ism()), + m_patch_num(m_pm), + m_patch_denom(m_pm), m_num_bool_vars(0), m_display_var(m_perm), m_explain(s, m_assignment, m_cache, m_atoms, m_var2eq, m_evaluator), @@ -202,6 +211,7 @@ namespace nlsat { m_max_conflicts = p.max_conflicts(); m_random_order = p.shuffle_vars(); m_random_seed = p.seed(); + m_inline_vars = p.inline_vars(); m_ism.set_seed(m_random_seed); m_explain.set_simplify_cores(m_simplify_cores); m_explain.set_minimize_cores(min_cores); @@ -330,9 +340,7 @@ namespace nlsat { */ bool_var max_bvar(clause const & cls) const { bool_var b = null_bool_var; - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = cls[i]; + for (literal l : cls) { if (b == null_bool_var || l.var() > b) b = l.var(); } @@ -367,9 +375,7 @@ namespace nlsat { if (x == null_var) return 0; unsigned max = 0; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = c[i]; + for (literal l : c) { atom const * a = m_atoms[l.var()]; if (a == 0) continue; @@ -496,13 +502,12 @@ namespace nlsat { // Delete atoms with ref_count == 0 void del_unref_atoms() { - unsigned sz = m_atoms.size(); - for (unsigned i = 0; i < sz; i++) { - del(m_atoms[i]); + for (auto* a : m_atoms) { + del(a); } } - bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + ineq_atom* mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even, bool& is_new) { SASSERT(sz >= 1); SASSERT(k == atom::LT || k == atom::GT || k == atom::EQ); int sign = 1; @@ -522,23 +527,36 @@ namespace nlsat { void * mem = m_allocator.allocate(ineq_atom::get_obj_size(sz)); if (sign < 0) k = atom::flip(k); - ineq_atom * new_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); + ineq_atom * tmp_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); TRACE("nlsat_table_bug", ineq_atom::hash_proc h; - tout << "mk_ineq_atom hash: " << h(new_atom) << "\n"; display(tout, *new_atom, m_display_var); tout << "\n";); - ineq_atom * old_atom = m_ineq_atoms.insert_if_not_there(new_atom); - CTRACE("nlsat_table_bug", old_atom->max_var() != max, display(tout, *old_atom, m_display_var); tout << "\n";); - SASSERT(old_atom->max_var() == max); - if (old_atom != new_atom) { - deallocate(new_atom); - return old_atom->bvar(); + tout << "mk_ineq_atom hash: " << h(tmp_atom) << "\n"; display(tout, *tmp_atom, m_display_var); tout << "\n";); + ineq_atom * atom = m_ineq_atoms.insert_if_not_there(tmp_atom); + CTRACE("nlsat_table_bug", atom->max_var() != max, display(tout, *atom, m_display_var); tout << "\n";); + SASSERT(atom->max_var() == max); + is_new = (atom == tmp_atom); + if (is_new) { + for (unsigned i = 0; i < sz; i++) { + m_pm.inc_ref(atom->p(i)); + } } - bool_var b = mk_bool_var_core(); - m_atoms[b] = new_atom; - new_atom->m_bool_var = b; - for (unsigned i = 0; i < sz; i++) { - m_pm.inc_ref(new_atom->p(i)); + else { + deallocate(tmp_atom); + } + return atom; + } + + bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + bool is_new = false; + ineq_atom* atom = mk_ineq_atom(k, sz, ps, is_even, is_new); + if (!is_new) { + return atom->bvar(); + } + else { + bool_var b = mk_bool_var_core(); + m_atoms[b] = atom; + atom->m_bool_var = b; + return b; } - return b; } literal mk_ineq_literal(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { @@ -619,10 +637,14 @@ namespace nlsat { deallocate(cls); } + void del_clause(clause * cls, clause_vector& clauses) { + clauses.erase(cls); + del_clause(cls); + } + void del_clauses(ptr_vector & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) - del_clause(cs[i]); + for (clause* cp : cs) + del_clause(cp); } void del_clauses() { @@ -732,18 +754,19 @@ namespace nlsat { } void undo_set_updt(interval_set * old_set) { - SASSERT(m_xk != null_var); + if (m_xk == null_var) return; var x = m_xk; - m_ism.dec_ref(m_infeasible[x]); - m_infeasible[x] = old_set; + if (x < m_infeasible.size()) { + m_ism.dec_ref(m_infeasible[x]); + m_infeasible[x] = old_set; + } } void undo_new_stage() { - SASSERT(m_xk != null_var); if (m_xk == 0) { m_xk = null_var; } - else { + else if (m_xk != null_var) { m_xk--; m_assignment.reset(m_xk); } @@ -756,8 +779,8 @@ namespace nlsat { } void undo_updt_eq(atom * a) { - SASSERT(m_xk != null_var); - m_var2eq[m_xk] = a; + if (m_var2eq.size() > m_xk) + m_var2eq[m_xk] = a; } template @@ -903,15 +926,18 @@ namespace nlsat { */ lbool value(literal l) { lbool val = assigned_value(l); - if (val != l_undef) + if (val != l_undef) { return val; + } bool_var b = l.var(); atom * a = m_atoms[b]; - if (a == 0) + if (a == 0) { return l_undef; + } var max = a->max_var(); - if (!m_assignment.is_assigned(max)) + if (!m_assignment.is_assigned(max)) { return l_undef; + } val = to_lbool(m_evaluator.eval(a, l.sign())); TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n"; @@ -923,10 +949,9 @@ namespace nlsat { \brief Return true if the given clause is already satisfied in the current partial interpretation. */ bool is_satisfied(clause const & cls) const { - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - if (const_cast(this)->value(cls[i]) == l_true) { - TRACE("value_bug:", tout << cls[i] << " := true\n";); + for (literal l : cls) { + if (const_cast(this)->value(l) == l_true) { + TRACE("value_bug:", tout << l << " := true\n";); return true; } } @@ -1019,14 +1044,14 @@ namespace nlsat { SASSERT(x != null_var); if (m_var2eq[x] != 0 && degree(m_var2eq[x]) <= degree(a)) return; // we only update m_var2eq if the new equality has smaller degree - TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x); tout << " (x" << x << ") "; + TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x) << " (x" << x << ") "; tout << "scope-lvl: " << scope_lvl() << "\n"; display(tout, literal(b, false)); tout << "\n";); save_updt_eq_trail(m_var2eq[x]); m_var2eq[x] = a; } /** - \brief Process a clause that contains nonlinar arithmetic literals + \brief Process a clause that contains nonlinear arithmetic literals If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0 */ @@ -1041,10 +1066,9 @@ namespace nlsat { interval_set_ref first_undef_set(m_ism); // infeasible region of the first undefined literal interval_set * xk_set = m_infeasible[m_xk]; // current set of infeasible interval for current variable SASSERT(!m_ism.is_full(xk_set)); - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned idx = 0; idx < cls.size(); ++idx) { + literal l = cls[idx]; checkpoint(); - literal l = cls[i]; if (value(l) == l_false) continue; SASSERT(value(l) == l_undef); @@ -1081,7 +1105,7 @@ namespace nlsat { } num_undef++; if (first_undef == UINT_MAX) { - first_undef = i; + first_undef = idx; first_undef_set = curr_set; } } @@ -1127,9 +1151,7 @@ namespace nlsat { Return 0, if the set was satisfied, or the violating clause otherwise */ clause * process_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause * c = cs[i]; + for (clause* c : cs) { if (!process_clause(*c, false)) return c; } @@ -1168,10 +1190,10 @@ namespace nlsat { void select_witness() { scoped_anum w(m_am); SASSERT(!m_ism.is_full(m_infeasible[m_xk])); - m_ism.peek_in_complement(m_infeasible[m_xk], w, m_randomize); + m_ism.peek_in_complement(m_infeasible[m_xk], m_is_int[m_xk], w, m_randomize); TRACE("nlsat", tout << "infeasible intervals: "; m_ism.display(tout, m_infeasible[m_xk]); tout << "\n"; - tout << "assigning "; m_display_var(tout, m_xk); tout << "(x" << m_xk << ") -> " << w << "\n";); + tout << "assigning "; m_display_var(tout, m_xk) << "(x" << m_xk << ") -> " << w << "\n";); TRACE("nlsat_root", tout << "value as root object: "; m_am.display_root(tout, w); tout << "\n";); if (!m_am.is_rational(w)) m_irrational_assignments++; @@ -1201,6 +1223,7 @@ namespace nlsat { TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";); if (m_bk == null_bool_var && m_xk >= num_vars()) { TRACE("nlsat", tout << "found model\n"; display_assignment(tout);); + fix_patch(); return l_true; // all variables were assigned, and all clauses were satisfied. } TRACE("nlsat", tout << "processing variable "; @@ -1232,12 +1255,69 @@ namespace nlsat { } } + lbool search_check() { + lbool r = l_undef; + while (true) { + r = search(); + if (r != l_true) break; + vector lows; + vector vars; + + for (var x = 0; x < num_vars(); x++) { + if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { + scoped_anum v(m_am), vlo(m_am); + v = m_assignment.value(x); + rational lo; + m_am.int_lt(v, vlo); + if (!m_am.is_int(vlo)) continue; + m_am.to_rational(vlo, lo); + // derive tight bounds. + while (true) { + lo++; + if (!m_am.gt(v, lo.to_mpq())) { lo--; break; } + } + lows.push_back(lo); + vars.push_back(x); + } + } + if (lows.empty()) break; + + init_search(); + for (unsigned i = 0; i < lows.size(); ++i) { + rational lo = lows[i]; + rational hi = lo + rational::one(); + var x = vars[i]; + bool is_even = false; + polynomial_ref p(m_pm); + rational one(1); + m_lemma.reset(); + p = m_pm.mk_linear(1, &one, &x, -lo); + poly* p1 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); + p = m_pm.mk_linear(1, &one, &x, -hi); + poly* p2 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + + // perform branch and bound + clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); + if (cls) { + TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); + } + } + } + return r; + } + lbool check() { TRACE("nlsat_smt2", display_smt2(tout);); TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";); init_search(); m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; + + if (!m_incremental && m_inline_vars) + simplify(); + if (!can_reorder()) { } @@ -1250,7 +1330,7 @@ namespace nlsat { reordered = true; } sort_watched_clauses(); - lbool r = search(); + lbool r = search_check(); CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout);); if (reordered) restore_order(); @@ -1440,9 +1520,9 @@ namespace nlsat { TRACE("nlsat_mathematica", display_mathematica_lemma(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr());); TRACE("nlsat_proof_sk", tout << "theory lemma\n"; display_abst(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); TRACE("nlsat_resolve", - tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk); tout << "\n"; + tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk) << "\n"; tout << "new valid clause:\n"; - display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); + display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()) << "\n";); DEBUG_CODE({ unsigned sz = m_lazy_clause.size(); @@ -1489,7 +1569,7 @@ namespace nlsat { max = lvl; } else { - // l must be a literal from a previous stage that is false in the current intepretation + // l must be a literal from a previous stage that is false in the current interpretation SASSERT(assigned_value(l) == l_undef); SASSERT(max_var(b) != null_var); SASSERT(m_xk != null_var); @@ -1576,15 +1656,10 @@ namespace nlsat { TRACE("nlsat_proof", tout << "STARTING RESOLUTION\n";); TRACE("nlsat_proof_sk", tout << "STARTING RESOLUTION\n";); m_conflicts++; - TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n"; + TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause) << "\n"; tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << ""; tout << "\n"; tout << "scope_lvl: " << scope_lvl() << "\n"; tout << "current assignment\n"; display_assignment(tout);); - - // static unsigned counter = 0; - // counter++; - // if (counter > 6) - // exit(0); m_num_marks = 0; m_lemma.reset(); @@ -1693,7 +1768,7 @@ namespace nlsat { SASSERT(m_xk == new_max_var); new_cls = mk_clause(sz, m_lemma.c_ptr(), true, m_lemma_assumptions.get()); TRACE("nlsat", tout << "new_level: " << scope_lvl() << "\nnew_stage: " << new_max_var << " "; - if (new_max_var != null_var) m_display_var(tout, new_max_var); tout << "\n";); + if (new_max_var != null_var) m_display_var(tout, new_max_var) << "\n";); } else { SASSERT(scope_lvl() >= 1); @@ -1815,7 +1890,7 @@ namespace nlsat { // ----------------------- // - // Variable reodering + // Variable reordering // // ----------------------- @@ -1874,11 +1949,12 @@ namespace nlsat { collect(*(cs[i])); } - void display(std::ostream & out, display_var_proc const & proc) { + std::ostream& display(std::ostream & out, display_var_proc const & proc) { unsigned sz = m_num_occs.size(); for (unsigned i = 0; i < sz; i++) { proc(out, i); out << " -> " << m_max_degree[i] << " : " << m_num_occs[i] << "\n"; } + return out; } }; @@ -1929,7 +2005,7 @@ namespace nlsat { for (var x = 0; x < num; x++) { p.push_back(x); } - random_gen r(m_random_seed); + random_gen r(++m_random_seed); shuffle(p.size(), p.c_ptr(), r); reorder(p.size(), p.c_ptr()); } @@ -2112,12 +2188,10 @@ namespace nlsat { } void reattach_arith_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause & c = *cs[i]; - var x = max_var(c); + for (clause* cp : cs) { + var x = max_var(*cp); if (x != null_var) - m_watches[x].push_back(&c); + m_watches[x].push_back(cp); } } @@ -2194,18 +2268,16 @@ namespace nlsat { } bool is_full_dimensional(clause const & c) const { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(c[i])) + for (literal l : c) { + if (!is_full_dimensional(l)) return false; } return true; } bool is_full_dimensional(clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(*(cs[i]))) + for (clause* c : cs) { + if (!is_full_dimensional(*c)) return false; } return true; @@ -2215,13 +2287,271 @@ namespace nlsat { return is_full_dimensional(m_clauses); } + + // ----------------------- + // + // Simplification + // + // ----------------------- + + // solve simple equalities + // TBD WU-Reit decomposition? + + /** + \brief isolate variables in unit equalities. + Assume a clause is c == v*p + q + and the context implies p > 0 + + replace v by -q/p + remove clause c, + The for other occurrences of v, + replace v*r + v*v*r' > 0 by + by p*p*v*r + p*p*v*v*r' > 0 + by p*q*r + q*q*r' > 0 + + The method ignores lemmas and assumes constraints don't use roots. + */ + + void simplify() { + polynomial_ref p(m_pm), q(m_pm); + var v; + init_var_signs(); + SASSERT(m_learned.empty()); + bool change = true; + while (change) { + change = false; + for (clause* c : m_clauses) { + if (solve_var(*c, v, p, q)) { + q = -q; + m_patch_var.push_back(v); + m_patch_num.push_back(q); + m_patch_denom.push_back(p); + del_clause(c, m_clauses); + substitute_var(v, p, q); + change = true; + break; + } + } + } + } + + void fix_patch() { + for (unsigned i = m_patch_var.size(); i-- > 0; ) { + var v = m_patch_var[i]; + poly* q = m_patch_num.get(i); + poly* p = m_patch_denom.get(i); + scoped_anum pv(m_am), qv(m_am), val(m_am); + m_pm.eval(p, m_assignment, pv); + m_pm.eval(q, m_assignment, qv); + val = qv / pv; + TRACE("nlsat", + m_display_var(tout << "patch ", v) << "\n"; + if (m_assignment.is_assigned(v)) m_am.display(tout << "previous value: ", m_assignment.value(v)); tout << "\n"; + m_am.display(tout << "updated value: ", val); tout << "\n"; + ); + m_assignment.set_core(v, val); + } + } + + void substitute_var(var x, poly* p, poly* q) { + polynomial_ref pr(m_pm); + polynomial_ref_vector ps(m_pm); + u_map b2l; + svector even; + unsigned num_atoms = m_atoms.size(); + for (unsigned j = 0; j < num_atoms; ++j) { + atom* a = m_atoms[j]; + if (a && a->is_ineq_atom()) { + ineq_atom const& a1 = *to_ineq_atom(a); + unsigned sz = a1.size(); + ps.reset(); + even.reset(); + bool change = false; + for (unsigned i = 0; i < sz; ++i) { + poly * po = a1.p(i); + m_pm.substitute(po, x, q, p, pr); + ps.push_back(pr); + even.push_back(a1.is_even(i)); + change |= pr != po; + if (m_pm.is_zero(pr)) { + ps.reset(); + even.reset(); + change = true; + break; + } + } + if (!change) continue; + literal l = mk_ineq_literal(a1.get_kind(), ps.size(), ps.c_ptr(), even.c_ptr()); + if (a1.m_bool_var != l.var()) { + b2l.insert(a1.m_bool_var, l); + inc_ref(l); + } + } + } + update_clauses(b2l); + for (auto const& kv : b2l) { + dec_ref(kv.m_value); + } + } + + + void update_clauses(u_map const& b2l) { + literal_vector lits; + clause_vector to_delete; + unsigned n = m_clauses.size(); + for (unsigned i = 0; i < n; ++i) { + clause* c = m_clauses[i]; + lits.reset(); + bool changed = false; + bool is_tautology = false; + for (literal l : *c) { + literal lit = null_literal; + if (b2l.find(l.var(), lit)) { + lit = l.sign() ? ~lit : lit; + if (lit == true_literal) { + is_tautology = true; + } + else if (lit != false_literal) { + lits.push_back(lit); + } + changed = true; + } + else { + lits.push_back(l); + } + } + if (changed) { + to_delete.push_back(c); + if (!is_tautology) { + mk_clause(lits.size(), lits.c_ptr(), c->is_learned(), static_cast<_assumption_set>(c->assumptions())); + } + } + } + for (clause* c : to_delete) { + del_clause(c, m_clauses); + } + } + + bool is_unit_ineq(clause const& c) const { + return + c.size() == 1 && + m_atoms[c[0].var()] && + m_atoms[c[0].var()]->is_ineq_atom(); + } + + bool is_unit_eq(clause const& c) const { + return + is_unit_ineq(c) && + !c[0].sign() && + m_atoms[c[0].var()]->is_eq(); + } + + /** + \brief determine whether the clause is a comparison v > k or v < k', where k >= 0 or k' <= 0. + */ + lbool is_cmp0(clause const& c, var& v) { + if (!is_unit_ineq(c)) return l_undef; + literal lit = c[0]; + ineq_atom const& a = *to_ineq_atom(m_atoms[lit.var()]); + bool sign = lit.sign(); + poly * p0; + if (!is_single_poly(a, p0)) return l_undef; + if (m_pm.is_var(p0, v)) { + if (!sign && a.get_kind() == atom::GT) { + return l_true; + } + if (!sign && a.get_kind() == atom::LT) { + return l_false; + } + return l_undef; + } + polynomial::scoped_numeral n(m_pm.m()); + if (m_pm.is_var_num(p0, v, n)) { + // x - k > 0 + if (!sign && a.get_kind() == atom::GT && m_pm.m().is_nonneg(n)) { + return l_true; + } + // x + k < 0 + if (!sign && a.get_kind() == atom::LT && m_pm.m().is_nonpos(n)) { + return l_false; + } + // !(x + k > 0) + if (sign && a.get_kind() == atom::GT && m_pm.m().is_pos(n)) { + return l_false; + } + // !(x - k < 0) + if (sign && a.get_kind() == atom::LT && m_pm.m().is_neg(n)) { + return l_true; + } + } + return l_undef; + } + + bool is_single_poly(ineq_atom const& a, poly*& p) { + unsigned sz = a.size(); + return sz == 1 && a.is_odd(0) && (p = a.p(0), true); + } + + svector m_var_signs; + + void init_var_signs() { + m_var_signs.reset(); + for (clause* cp : m_clauses) { + clause& c = *cp; + var x = 0; + lbool cmp = is_cmp0(c, x); + switch (cmp) { + case l_true: + m_var_signs.setx(x, l_true, l_undef); + break; + case l_false: + m_var_signs.setx(x, l_false, l_undef); + break; + default: + break; + } + } + } + + /** + \brief returns true then c is an equality that is equivalent to v*p + q, + and p > 0, v does not occur in p, q. + */ + bool solve_var(clause& c, var& v, polynomial_ref& p, polynomial_ref& q) { + poly* p0; + if (!is_unit_eq(c)) return false; + ineq_atom & a = *to_ineq_atom(m_atoms[c[0].var()]); + if (!is_single_poly(a, p0)) return false; + var mx = max_var(p0); + if (mx >= m_is_int.size()) return false; + for (var x = 0; x <= mx; ++x) { + if (m_is_int[x]) continue; + if (1 == m_pm.degree(p0, x)) { + p = m_pm.coeff(p0, x, 1, q); + switch (m_pm.sign(p, m_var_signs)) { + case l_true: + v = x; + return true; + case l_false: + v = x; + p = -p; + q = -q; + return true; + default: + break; + } + } + } + return false; + } + // ----------------------- // // Pretty printing // // ----------------------- - void display_num_assignment(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display_num_assignment(std::ostream & out, display_var_proc const & proc) const { for (var x = 0; x < num_vars(); x++) { if (m_assignment.is_assigned(x)) { proc(out, x); @@ -2230,9 +2560,10 @@ namespace nlsat { out << "\n"; } } + return out; } - void display_bool_assignment(std::ostream & out) const { + std::ostream& display_bool_assignment(std::ostream & out) const { unsigned sz = m_atoms.size(); for (bool_var b = 0; b < sz; b++) { if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) { @@ -2243,6 +2574,7 @@ namespace nlsat { for (bool_var b = 0; b < sz; b++) { out << "b" << b << " -> " << m_bvalues[b] << " " << m_atoms[b] << "\n"; }); + return out; } bool display_mathematica_assignment(std::ostream & out) const { @@ -2260,16 +2592,17 @@ namespace nlsat { return !first; } - void display_num_assignment(std::ostream & out) const { - display_num_assignment(out, m_display_var); + std::ostream& display_num_assignment(std::ostream & out) const { + return display_num_assignment(out, m_display_var); } - void display_assignment(std::ostream& out) const { + std::ostream& display_assignment(std::ostream& out) const { display_bool_assignment(out); display_num_assignment(out); + return out; } - void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { + std::ostream& display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (use_star && i > 0) @@ -2289,9 +2622,10 @@ namespace nlsat { case atom::EQ: out << " = 0"; break; default: UNREACHABLE(); break; } + return out; } - - void display_mathematica(std::ostream & out, ineq_atom const & a) const { + + std::ostream& display_mathematica(std::ostream & out, ineq_atom const & a) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) @@ -2313,9 +2647,10 @@ namespace nlsat { case atom::EQ: out << " == 0"; break; default: UNREACHABLE(); break; } + return out; } - void display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { switch (a.get_kind()) { case atom::LT: out << "(< "; break; case atom::GT: out << "(> "; break; @@ -2341,9 +2676,10 @@ namespace nlsat { if (sz > 1) out << ")"; out << " 0)"; + return out; } - void display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { proc(out, a.x()); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2356,21 +2692,22 @@ namespace nlsat { out << "root[" << a.i() << "]("; m_pm.display(out, a.p(), proc); out << ")"; + return out; } struct mathematica_var_proc : public display_var_proc { var m_x; public: mathematica_var_proc(var x):m_x(x) {} - virtual void operator()(std::ostream & out, var x) const { + virtual std::ostream& operator()(std::ostream & out, var x) const { if (m_x == x) - out << "#1"; + return out << "#1"; else - out << "x" << x; + return out << "x" << x; } }; - void display_mathematica(std::ostream & out, root_atom const & a) const { + std::ostream& display_mathematica(std::ostream & out, root_atom const & a) const { out << "x" << a.x(); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2383,65 +2720,74 @@ namespace nlsat { out << "Root["; m_pm.display(out, a.p(), mathematica_var_proc(a.x()), true); out << " &, " << a.i() << "]"; + return out; } - void display_smt2(std::ostream & out, root_atom const & a) const { + std::ostream& display_smt2(std::ostream & out, root_atom const & a) const { NOT_IMPLEMENTED_YET(); + return out; } - void display(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, atom const & a, display_var_proc const & proc) const { if (a.is_ineq_atom()) - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); else - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); } - void display_mathematica(std::ostream & out, atom const & a) const { - if (a.is_ineq_atom()) - display_mathematica(out, static_cast(a)); - else - display_mathematica(out, static_cast(a)); + std::ostream& display(std::ostream & out, atom const & a) const { + return display(out, a, m_display_var); } - void display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display_mathematica(std::ostream & out, atom const & a) const { if (a.is_ineq_atom()) - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); else - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); } - void display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + if (a.is_ineq_atom()) + return display_smt2(out, static_cast(a), proc); + else + return display_smt2(out, static_cast(a), proc); + } + + std::ostream& display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display(out, *(m_atoms[b]), proc); + return out; } - void display_atom(std::ostream & out, bool_var b) const { - display_atom(out, b, m_display_var); + std::ostream& display_atom(std::ostream & out, bool_var b) const { + return display_atom(out, b, m_display_var); } - void display_mathematica_atom(std::ostream & out, bool_var b) const { + std::ostream& display_mathematica_atom(std::ostream & out, bool_var b) const { if (b == 0) out << "(0 < 1)"; else if (m_atoms[b] == 0) out << "b" << b; else display_mathematica(out, *(m_atoms[b])); + return out; } - void display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display_smt2(out, *(m_atoms[b]), proc); + return out; } - void display(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2454,13 +2800,14 @@ namespace nlsat { else { display_atom(out, l.var(), proc); } + return out; } - void display(std::ostream & out, literal l) const { - display(out, l, m_display_var); + std::ostream& display(std::ostream & out, literal l) const { + return display(out, l, m_display_var); } - void display_mathematica(std::ostream & out, literal l) const { + std::ostream& display_mathematica(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2473,9 +2820,10 @@ namespace nlsat { else { display_mathematica_atom(out, l.var()); } + return out; } - void display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "(not "; @@ -2485,41 +2833,43 @@ namespace nlsat { else { display_smt2_atom(out, l.var(), proc); } + return out; } - void display_assumptions(std::ostream & out, _assumption_set s) const { - + std::ostream& display_assumptions(std::ostream & out, _assumption_set s) const { + return out; } - void display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display(out, ls[i], proc); } + return out; } - void display(std::ostream & out, unsigned num, literal const * ls) { - display(out, num, ls, m_display_var); + std::ostream& display(std::ostream & out, unsigned num, literal const * ls) { + return display(out, num, ls, m_display_var); + } + + std::ostream& display(std::ostream & out, scoped_literal_vector const & cs) { + return display(out, cs.size(), cs.c_ptr(), m_display_var); } - void display(std::ostream & out, scoped_literal_vector const & cs) { - display(out, cs.size(), cs.c_ptr(), m_display_var); - } - - void display(std::ostream & out, clause const & c, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, clause const & c, display_var_proc const & proc) const { if (c.assumptions() != 0) { display_assumptions(out, static_cast<_assumption_set>(c.assumptions())); out << " |- "; } - display(out, c.size(), c.c_ptr(), proc); + return display(out, c.size(), c.c_ptr(), proc); } - void display(std::ostream & out, clause const & c) const { - display(out, c, m_display_var); + std::ostream& display(std::ostream & out, clause const & c) const { + return display(out, c, m_display_var); } - void display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { if (num == 0) { out << "false"; } @@ -2534,13 +2884,14 @@ namespace nlsat { } out << ")"; } + return out; } - void display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { - display_smt2(out, c.size(), c.c_ptr(), proc); + std::ostream& display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { + return display_smt2(out, c.size(), c.c_ptr(), proc); } - void display_abst(std::ostream & out, literal l) const { + std::ostream& display_abst(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2552,25 +2903,27 @@ namespace nlsat { else { out << "b" << l.var(); } + return out; } - void display_abst(std::ostream & out, unsigned num, literal const * ls) const { + std::ostream& display_abst(std::ostream & out, unsigned num, literal const * ls) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display_abst(out, ls[i]); } + return out; } - void display_abst(std::ostream & out, scoped_literal_vector const & cs) const { - display_abst(out, cs.size(), cs.c_ptr()); + std::ostream& display_abst(std::ostream & out, scoped_literal_vector const & cs) const { + return display_abst(out, cs.size(), cs.c_ptr()); } - void display_abst(std::ostream & out, clause const & c) const { - display_abst(out, c.size(), c.c_ptr()); + std::ostream& display_abst(std::ostream & out, clause const & c) const { + return display_abst(out, c.size(), c.c_ptr()); } - void display_mathematica(std::ostream & out, clause const & c) const { + std::ostream& display_mathematica(std::ostream & out, clause const & c) const { out << "("; unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { @@ -2579,12 +2932,13 @@ namespace nlsat { display_mathematica(out, c[i]); } out << ")"; + return out; } // Debugging support: // Display generated lemma in Mathematica format. // Mathematica must reduce lemma to True (modulo resource constraints). - void display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { + std::ostream& display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { out << "Resolve[ForAll[{"; // var definition for (unsigned i = 0; i < num_vars(); i++) { @@ -2605,71 +2959,69 @@ namespace nlsat { display_mathematica(out, ls[i]); } out << "], Reals]\n"; // end of exists + return out; } - void display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display(out, *(cs[i]), proc); - out << "\n"; + std::ostream& display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { + for (clause* c : cs) { + display(out, *c, proc) << "\n"; } + return out; } - void display(std::ostream & out, clause_vector const & cs) const { - display(out, cs, m_display_var); + std::ostream& display(std::ostream & out, clause_vector const & cs) const { + return display(out, cs, m_display_var); } - void display_mathematica(std::ostream & out, clause_vector const & cs) const { + std::ostream& display_mathematica(std::ostream & out, clause_vector const & cs) const { unsigned sz = cs.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) out << ",\n"; - out << " "; - display_mathematica(out, *(cs[i])); + display_mathematica(out << " ", *(cs[i])); } + return out; } - void display_abst(std::ostream & out, clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display_abst(out, *(cs[i])); - out << "\n"; + std::ostream& display_abst(std::ostream & out, clause_vector const & cs) const { + for (clause* c : cs) { + display_abst(out, *c) << "\n"; } + return out; } - void display(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, display_var_proc const & proc) const { display(out, m_clauses, proc); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display(out, m_learned, proc); + display(out << "Lemmas:\n", m_learned, proc); } + return out; } - void display_mathematica(std::ostream & out) const { - out << "{\n"; - display_mathematica(out, m_clauses); - out << "}\n"; + std::ostream& display_mathematica(std::ostream & out) const { + return display_mathematica(out << "{\n", m_clauses) << "}\n"; } - void display_abst(std::ostream & out) const { + std::ostream& display_abst(std::ostream & out) const { display_abst(out, m_clauses); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display_abst(out, m_learned); + display_abst(out << "Lemmas:\n", m_learned); } + return out; } - void display(std::ostream & out) const { + std::ostream& display(std::ostream & out) const { display(out, m_display_var); - display_assignment(out); + return display_assignment(out); } - void display_vars(std::ostream & out) const { + std::ostream& display_vars(std::ostream & out) const { for (unsigned i = 0; i < num_vars(); i++) { out << i << " -> "; m_display_var(out, i); out << "\n"; } + return out; } - void display_smt2_arith_decls(std::ostream & out) const { + std::ostream& display_smt2_arith_decls(std::ostream & out) const { unsigned sz = m_is_int.size(); for (unsigned i = 0; i < sz; i++) { if (m_is_int[i]) @@ -2677,31 +3029,32 @@ namespace nlsat { else out << "(declare-fun x" << i << " () Real)\n"; } + return out; } - void display_smt2_bool_decls(std::ostream & out) const { + std::ostream& display_smt2_bool_decls(std::ostream & out) const { unsigned sz = m_atoms.size(); for (unsigned i = 0; i < sz; i++) { if (m_atoms[i] == 0) out << "(declare-fun b" << i << " () Bool)\n"; } + return out; } - void display_smt2(std::ostream & out) const { + std::ostream& display_smt2(std::ostream & out) const { display_smt2_bool_decls(out); display_smt2_arith_decls(out); out << "(assert (and true\n"; - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; i++) { - display_smt2(out, *(m_clauses[i])); - out << "\n"; + for (clause* c : m_clauses) { + display_smt2(out, *c) << "\n"; } out << "))\n(check-sat)" << std::endl; + return out; } }; - solver::solver(reslimit& rlim, params_ref const & p) { - m_imp = alloc(imp, *this, rlim, p); + solver::solver(reslimit& rlim, params_ref const & p, bool incremental) { + m_imp = alloc(imp, *this, rlim, p, incremental); } solver::~solver() { diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index ac503c603..c632a0334 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -35,7 +35,7 @@ namespace nlsat { struct imp; imp * m_imp; public: - solver(reslimit& rlim, params_ref const & p); + solver(reslimit& rlim, params_ref const & p, bool incremental); ~solver(); /** diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 8704f4444..647a5e3ee 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -47,6 +47,8 @@ namespace nlsat { typedef polynomial::var_vector var_vector; typedef polynomial::manager pmanager; typedef polynomial::polynomial poly; + typedef polynomial::monomial monomial; + typedef polynomial::numeral numeral; const var null_var = polynomial::null_var; const var true_bool_var = 0; @@ -148,10 +150,7 @@ namespace nlsat { typedef algebraic_numbers::anum anum; typedef algebraic_numbers::manager anum_manager; - class solver_exception : public default_exception { - public: - solver_exception(char const * msg):default_exception(msg) {} - }; + typedef default_exception solver_exception; class assignment; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 510f503e7..9de7215e3 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -32,11 +32,11 @@ class nlsat_tactic : public tactic { ast_manager & m; expr_ref_vector m_var2expr; expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {} - virtual void operator()(std::ostream & out, nlsat::var x) const { + virtual std::ostream& operator()(std::ostream & out, nlsat::var x) const { if (x < m_var2expr.size()) - out << mk_ismt2_pp(m_var2expr.get(x), m); + return out << mk_ismt2_pp(m_var2expr.get(x), m); else - out << "x!" << x; + return out << "x!" << x; } }; @@ -51,7 +51,7 @@ class nlsat_tactic : public tactic { m(_m), m_params(p), m_display_var(_m), - m_solver(m.limit(), p) { + m_solver(m.limit(), p, false) { } void updt_params(params_ref const & p) { diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index 22f64af47..47b9e0505 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -48,11 +48,15 @@ tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { purify_p), mk_propagate_values_tactic(m, p), mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), mk_elim_uncnstr_tactic(m, p), mk_elim_term_ite_tactic(m, p)), and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection factor, mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), using_params(mk_simplify_tactic(m, p), main_p), mk_tseitin_cnf_core_tactic(m, p), diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index 05a62b6c2..28a14be2e 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(opt opt_cmds.cpp opt_context.cpp opt_pareto.cpp + opt_parse.cpp optsmt.cpp opt_solver.cpp pb_sls.cpp diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8d73ea7c8..0daf98320 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -345,12 +345,24 @@ namespace opt { fix_model(mdl); } + bool context::contains_quantifiers() const { + for (expr* f : m_hard_constraints) { + if (has_quantifiers(f)) return true; + } + return false; + } + + lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) { if (scoped) get_solver().push(); lbool result = m_optsmt.lex(index, is_max); if (result == l_true) m_optsmt.get_model(m_model, m_labels); if (scoped) get_solver().pop(1); if (result == l_true && committed) m_optsmt.commit_assignment(index); + if (result == l_true && m_optsmt.is_unbounded(index, is_max) && contains_quantifiers()) { + throw default_exception("unbounded objectives on quantified constraints is not supported"); + result = l_undef; + } return result; } @@ -646,8 +658,7 @@ namespace opt { expr_fast_mark1 visited; is_bv proc(m); try { - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective & obj = m_objectives[i]; + for (objective& obj : m_objectives) { if (obj.m_type != O_MAXSMT) return false; maxsmt& ms = *m_maxsmts.find(obj.m_id); for (unsigned j = 0; j < ms.size(); ++j) { @@ -658,8 +669,8 @@ namespace opt { for (unsigned i = 0; i < sz; i++) { quick_for_each_expr(proc, visited, get_solver().get_assertion(i)); } - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - quick_for_each_expr(proc, visited, m_hard_constraints[i].get()); + for (expr* f : m_hard_constraints) { + quick_for_each_expr(proc, visited, f); } } catch (is_bv::found) { @@ -1224,6 +1235,9 @@ namespace opt { } void context::display_assignment(std::ostream& out) { + if (m_scoped_state.m_objectives.size() != m_objectives.size()) { + throw default_exception("check-sat has not been called with latest objectives"); + } out << "(objectives\n"; for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { objective const& obj = m_scoped_state.m_objectives[i]; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index ad40db074..1ae60ef87 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -233,13 +233,14 @@ namespace opt { private: lbool execute(objective const& obj, bool committed, bool scoped); - lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); + lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); lbool execute_maxsat(symbol const& s, bool committed, bool scoped); lbool execute_lex(); lbool execute_box(); lbool execute_pareto(); lbool adjust_unknown(lbool r); bool scoped_lex(); + bool contains_quantifiers() const; expr_ref to_expr(inf_eps const& n); void to_exprs(inf_eps const& n, expr_ref_vector& es); diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp new file mode 100644 index 000000000..2cba7561f --- /dev/null +++ b/src/opt/opt_parse.cpp @@ -0,0 +1,317 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + opt_parse.cpp + +Abstract: + + Parse utilities for optimization. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#include "opt/opt_context.h" +#include "opt/opt_parse.h" + + +class opt_stream_buffer { + std::istream & m_stream; + int m_val; + unsigned m_line; +public: + opt_stream_buffer(std::istream & s): + m_stream(s), + m_line(0) { + m_val = m_stream.get(); + } + int operator *() const { return m_val;} + void operator ++() { m_val = m_stream.get(); } + int ch() const { return m_val; } + void next() { m_val = m_stream.get(); } + bool eof() const { return ch() == EOF; } + unsigned line() const { return m_line; } + void skip_whitespace(); + void skip_space(); + void skip_line(); + bool parse_token(char const* token); + int parse_int(); + unsigned parse_unsigned(); +}; + + +void opt_stream_buffer::skip_whitespace() { + while ((ch() >= 9 && ch() <= 13) || ch() == 32) { + if (ch() == 10) ++m_line; + next(); + } +} + +void opt_stream_buffer::skip_space() { + while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { + next(); + } +} +void opt_stream_buffer::skip_line() { + while(true) { + if (eof()) { + return; + } + if (ch() == '\n') { + ++m_line; + next(); + return; + } + next(); + } +} + +bool opt_stream_buffer::parse_token(char const* token) { + skip_whitespace(); + char const* t = token; + while (ch() == *t) { + next(); + ++t; + } + return 0 == *t; +} + +unsigned opt_stream_buffer::parse_unsigned() { + skip_space(); + if (ch() == '\n') { + return UINT_MAX; + } + unsigned val = 0; + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return val; +} + +int opt_stream_buffer::parse_int() { + int val = 0; + bool neg = false; + skip_whitespace(); + + if (ch() == '-') { + neg = true; + next(); + } + else if (ch() == '+') { + next(); + } + if (ch() < '0' || ch() > '9') { + std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; + exit(3); + } + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return neg ? -val : val; +} + + +class wcnf { + opt::context& opt; + ast_manager& m; + opt_stream_buffer& in; + unsigned_vector& m_handles; + + app_ref read_clause(unsigned& weight) { + int parsed_lit; + int var; + weight = in.parse_unsigned(); + app_ref result(m), p(m); + expr_ref_vector ors(m); + while (true) { + parsed_lit = in.parse_int(); + if (parsed_lit == 0) + break; + var = abs(parsed_lit); + p = m.mk_const(symbol(var), m.mk_bool_sort()); + if (parsed_lit < 0) p = m.mk_not(p); + ors.push_back(p); + } + result = to_app(mk_or(m, ors.size(), ors.c_ptr())); + return result; + } + + void parse_spec(unsigned& num_vars, unsigned& num_clauses, unsigned& max_weight) { + in.parse_token("wcnf"); + num_vars = in.parse_unsigned(); + num_clauses = in.parse_unsigned(); + max_weight = in.parse_unsigned(); + } + +public: + + wcnf(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h): opt(opt), m(opt.get_manager()), in(in), m_handles(h) { + opt.set_clausal(true); + } + + void parse() { + unsigned num_vars = 0, num_clauses = 0, max_weight = 0; + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == 'c') { + in.skip_line(); + } + else if (*in == 'p') { + ++in; + parse_spec(num_vars, num_clauses, max_weight); + } + else { + unsigned weight = 0; + app_ref cls = read_clause(weight); + if (weight >= max_weight) { + opt.add_hard_constraint(cls); + } + else { + unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); + if (m_handles.empty()) { + m_handles.push_back(id); + } + } + } + } + } +}; + + +class opb { + opt::context& opt; + ast_manager& m; + opt_stream_buffer& in; + unsigned_vector& m_handles; + arith_util arith; + + app_ref parse_id() { + bool negated = in.parse_token("~"); + if (!in.parse_token("x")) { + std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\" expected \"x\")\n"; + exit(3); + } + app_ref p(m); + int id = in.parse_int(); + p = m.mk_const(symbol(id), m.mk_bool_sort()); + if (negated) p = m.mk_not(p); + in.skip_whitespace(); + return p; + } + + app_ref parse_ids() { + app_ref result = parse_id(); + while (*in == '~' || *in == 'x') { + result = m.mk_and(result, parse_id()); + } + return result; + } + + rational parse_coeff_r() { + in.skip_whitespace(); + svector num; + bool pos = true; + if (*in == '-') pos = false, ++in; + if (*in == '+') ++in; + if (!pos) num.push_back('-'); + in.skip_whitespace(); + while ('0' <= *in && *in <='9') num.push_back(*in), ++in; + num.push_back(0); + return rational(num.c_ptr()); + } + + app_ref parse_coeff() { + return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); + } + + app_ref parse_term() { + app_ref c = parse_coeff(); + app_ref e = parse_ids(); + return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); + } + + void parse_objective(bool is_min) { + app_ref t = parse_term(); + while (!in.parse_token(";") && !in.eof()) { + if (is_min) { + t = arith.mk_add(t, parse_term()); + } + else { + t = arith.mk_sub(t, parse_term()); + } + } + m_handles.push_back(opt.add_objective(t, false)); + } + + void parse_constraint() { + app_ref t = parse_term(); + while (!in.eof()) { + if (in.parse_token(">=")) { + t = arith.mk_ge(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("=")) { + t = m.mk_eq(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("<=")) { + t = arith.mk_le(t, parse_coeff()); + in.parse_token(";"); + break; + } + t = arith.mk_add(t, parse_term()); + } + opt.add_hard_constraint(t); + } +public: + opb(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h): + opt(opt), m(opt.get_manager()), + in(in), m_handles(h), arith(m) {} + + void parse() { + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == '*') { + in.skip_line(); + } + else if (in.parse_token("min:")) { + parse_objective(true); + } + else if (in.parse_token("max:")) { + parse_objective(false); + } + else { + parse_constraint(); + } + } + } +}; + +void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + wcnf w(opt, _is, h); + w.parse(); +} + +void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + opb opb(opt, _is, h); + opb.parse(); +} + + diff --git a/src/opt/opt_parse.h b/src/opt/opt_parse.h new file mode 100644 index 000000000..b058efcac --- /dev/null +++ b/src/opt/opt_parse.h @@ -0,0 +1,28 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + opt_parse.h + +Abstract: + + Parse utilities for optimization. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#ifndef OPT_PARSE_H_ +#define OPT_PARSE_H_ + +void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h); + +void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h); + +#endif /* OPT_PARSE_H_ */ + + diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f8f75fbfd..3258cb33d 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -161,6 +161,14 @@ namespace opt { return l_true; } + bool optsmt::is_unbounded(unsigned obj_index, bool is_maximize) { + if (is_maximize) { + return !m_upper[obj_index].is_finite(); + } + else { + return !m_lower[obj_index].is_finite(); + } + } lbool optsmt::geometric_lex(unsigned obj_index, bool is_maximize) { arith_util arith(m); diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 921352898..93fa3f624 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -49,6 +49,8 @@ namespace opt { lbool lex(unsigned obj_index, bool is_maximize); + bool is_unbounded(unsigned obj_index, bool is_maximize); + unsigned add(app* t); void updt_params(params_ref& p); diff --git a/src/parsers/smt/CMakeLists.txt b/src/parsers/smt/CMakeLists.txt deleted file mode 100644 index 2edf7b679..000000000 --- a/src/parsers/smt/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -z3_add_component(smtparser - SOURCES - smtlib.cpp - smtlib_solver.cpp - smtparser.cpp - COMPONENT_DEPENDENCIES - portfolio -) diff --git a/src/parsers/smt/smtlib.cpp b/src/parsers/smt/smtlib.cpp deleted file mode 100644 index 71dd48156..000000000 --- a/src/parsers/smt/smtlib.cpp +++ /dev/null @@ -1,258 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - - -#include "parsers/smt/smtlib.h" -#include "ast/ast_pp.h" -#include "ast/ast_smt2_pp.h" - -#ifdef _WINDOWS -#ifdef ARRAYSIZE -#undef ARRAYSIZE -#endif -#include -#include -#endif - -#include - - -using namespace smtlib; - -// -------------------------------------------------------------------------- -// symtable - -symtable::~symtable() { - reset(); -} - -void symtable::reset() { - svector*> range; - m_ids.get_range(range); - for (unsigned i = 0; i < range.size(); ++i) { - ptr_vector const & v = *range[i]; - for (unsigned j = 0; j < v.size(); ++j) { - m_manager.dec_ref(v[j]); - } - dealloc(range[i]); - } - m_ids.reset(); - ptr_vector sorts; - m_sorts1.get_range(sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - m_manager.dec_ref(sorts[i]); - } - m_sorts1.reset(); - ptr_vector sort_builders; - m_sorts.get_range(sort_builders); - for (unsigned i = 0; i < sort_builders.size(); ++i) { - dealloc(sort_builders[i]); - } - m_sorts.reset(); -} - - -void symtable::insert(symbol s, func_decl * d) { - ptr_vector* decls = 0; - m_manager.inc_ref(d); - if (!m_ids.find(s, decls)) { - SASSERT(!decls); - decls = alloc(ptr_vector); - decls->push_back(d); - m_ids.insert(s, decls); - } - else { - SASSERT(decls); - if ((*decls)[0] != d) { - decls->push_back(d); - } - else { - m_manager.dec_ref(d); - } - } -} - -bool symtable::find1(symbol s, func_decl*& d) { - ptr_vector* decls = 0; - - if (!m_ids.find(s, decls)) { - SASSERT(!decls); - return false; - } - SASSERT(decls && !decls->empty()); - d = (*decls)[0]; - return true; -} - -bool symtable::find_overload(symbol s, ptr_vector const & dom, func_decl * & d) { - ptr_vector* decls = 0; - d = 0; - if (!m_ids.find(s, decls)) { - SASSERT(!decls); - return false; - } - SASSERT(decls); - for (unsigned i = 0; i < decls->size(); ++i) { - func_decl* decl = (*decls)[i]; - if (decl->is_associative() && decl->get_arity() > 0) { - for (unsigned j = 0; j < dom.size(); ++j) { - if (dom[j] != decl->get_domain(0)) { - goto try_next; - } - } - d = decl; - return true; - } - - if (decl->get_arity() != dom.size()) { - goto try_next; - } - for (unsigned j = 0; j < decl->get_arity(); ++j) { - if (decl->get_domain(j) != dom[j]) { - goto try_next; - } - } - d = decl; - return true; - - try_next: - if (decl->get_family_id() == m_manager.get_basic_family_id() && decl->get_decl_kind() == OP_DISTINCT) { - // we skip type checking for 'distinct' - d = decl; - return true; - } - } - return false; -} - -// Store in result the func_decl that are not attached to any family id. -// That is, the uninterpreted constants and function declarations. -void symtable::get_func_decls(ptr_vector & result) const { - svector*> tmp; - m_ids.get_range(tmp); - svector*>::const_iterator it = tmp.begin(); - svector*>::const_iterator end = tmp.end(); - for (; it != end; ++it) { - ptr_vector * curr = *it; - if (curr) { - ptr_vector::const_iterator it2 = curr->begin(); - ptr_vector::const_iterator end2 = curr->end(); - for (; it2 != end2; ++it2) { - func_decl * d = *it2; - if (d && d->get_family_id() == null_family_id) { - result.push_back(d); - } - } - } - } -} - -void symtable::insert(symbol s, sort_builder* sb) { - m_sorts.insert(s, sb); -} - -bool symtable::lookup(symbol s, sort_builder*& sb) { - return m_sorts.find(s, sb); -} - -void symtable::push_sort(symbol name, sort* srt) { - m_sorts.begin_scope(); - sort_builder* sb = alloc(basic_sort_builder,srt); - m_sorts.insert(name, sb); - m_sorts_trail.push_back(sb); -} - -void symtable::pop_sorts(unsigned num_sorts) { - while (num_sorts > 0) { - dealloc(m_sorts_trail.back()); - m_sorts_trail.pop_back(); - m_sorts.end_scope(); - } -} - -void symtable::get_sorts(ptr_vector& result) const { - vector tmp; - m_sorts1.get_range(tmp); - for (unsigned i = 0; i < tmp.size(); ++i) { - if (tmp[i]->get_family_id() == null_family_id) { - result.push_back(tmp[i]); - } - } -} - - -// -------------------------------------------------------------------------- -// theory - -func_decl * theory::declare_func(symbol const & id, sort_ref_buffer & domain, sort * range, - bool is_assoc, bool is_comm, bool is_inj) { - func_decl * decl = m_ast_manager.mk_func_decl(id, domain.size(), domain.c_ptr(), range, - is_assoc, is_comm, is_inj); - - m_symtable.insert(id, decl); - m_asts.push_back(decl); - return decl; -} - - -sort * theory::declare_sort(symbol const & id) { - sort * decl = m_ast_manager.mk_uninterpreted_sort(id); - m_symtable.insert(id, decl); - m_asts.push_back(decl); - return decl; -} - - -bool theory::get_func_decl(symbol id, func_decl * & decl) { - return m_symtable.find1(id, decl); -} - -bool theory::get_sort(symbol id, sort* & s) { - return m_symtable.find(id, s); -} - -bool theory::get_const(symbol id, expr * & term) { - func_decl* decl = 0; - if (!get_func_decl(id,decl)) { - return false; - } - if (decl->get_arity() != 0) { - return false; - } - term = m_ast_manager.mk_const(decl); - m_asts.push_back(term); - return true; -} - -void benchmark::display_as_smt2(std::ostream & out) const { - if (m_logic != symbol::null) - out << "(set-logic " << m_logic << ")\n"; - out << "(set-info :smt-lib-version 2.0)\n"; - out << "(set-info :status "; - switch (m_status) { - case SAT: out << "sat"; break; - case UNSAT: out << "unsat"; break; - default: out << "unknown"; break; - } - out << ")\n"; -#if 0 - ast_manager & m = m_ast_manager; - ptr_vector decls; - m_symtable.get_func_decls(decls); - ptr_vector::const_iterator it = decls.begin(); - ptr_vector::const_iterator end = decls.end(); - for (; it != end; ++it) { - func_decl * f = *it; - out << "(declare-fun " << f->get_name() << " ("; - for (unsigned i = 0; i < f->get_arity(); i++) { - if (i > 0) out << " "; - out << mk_ismt2_pp(f->get_domain(i), m); - } - out << ") " << mk_ismt2_pp(f->get_range(), m); - out << ")\n"; - } -#endif -} diff --git a/src/parsers/smt/smtlib.h b/src/parsers/smt/smtlib.h deleted file mode 100644 index f037e3d74..000000000 --- a/src/parsers/smt/smtlib.h +++ /dev/null @@ -1,232 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtlib.h - -Abstract: - - SMT library utilities - -Author: - - Nikolaj Bjorner (nbjorner) 2006-09-29 - -Revision History: - ---*/ -#ifndef SMTLIB_H_ -#define SMTLIB_H_ - -#include "ast/ast.h" -#include "util/symbol_table.h" -#include "util/map.h" -#include "ast/arith_decl_plugin.h" - -namespace smtlib { - - class sort_builder { - public: - virtual ~sort_builder() {} - virtual bool apply(unsigned num_params, parameter const* params, sort_ref& result) = 0; - virtual char const* error_message() { return ""; } - }; - - class basic_sort_builder : public sort_builder { - sort* m_sort; - public: - basic_sort_builder(sort* s) : m_sort(s) {} - - virtual bool apply(unsigned np, parameter const*, sort_ref& result) { - result = m_sort; - return m_sort && np != 0; - } - }; - - - class symtable { - ast_manager& m_manager; - symbol_table m_sorts1; - symbol_table m_sorts; - ptr_vector m_sorts_trail; - symbol_table* > m_ids; - - public: - - symtable(ast_manager& m): m_manager(m) {} - - ~symtable(); - - void reset(); - - void insert(symbol s, func_decl * d); - - bool find(symbol s, ptr_vector * & decls) { - return m_ids.find(s, decls); - } - - bool find1(symbol s, func_decl * & d); - - bool find_overload(symbol s, ptr_vector const & dom, func_decl * & d); - - void insert(symbol s, sort * d) { - sort * d2; - if (m_sorts1.find(s, d2)) { - m_manager.dec_ref(d2); - } - m_manager.inc_ref(d); - m_sorts1.insert(s, d); - } - - bool find(symbol s, sort * & d) { - return m_sorts1.find(s, d); - } - - void insert(symbol s, sort_builder* sb); - - bool lookup(symbol s, sort_builder*& sb); - - void push_sort(symbol s, sort*); - - void pop_sorts(unsigned num_sorts); - - void get_func_decls(ptr_vector & result) const; - - void get_sorts(ptr_vector& result) const; - }; - - class theory { - public: - typedef ptr_vector::const_iterator expr_iterator; - - theory(ast_manager & ast_manager, symbol const& name): - m_name(name), - m_ast_manager(ast_manager), - m_symtable(ast_manager), - m_asts(ast_manager) - {} - - virtual ~theory() {} - - symtable * get_symtable() { return &m_symtable; } - - void insert(sort * s) { m_symtable.insert(s->get_name(), s); } - - void insert(func_decl * c) { m_symtable.insert(c->get_name(), c); } - - func_decl * declare_func(symbol const & id, sort_ref_buffer & domain, sort * range, - bool is_assoc, bool is_comm, bool is_inj); - - sort * declare_sort(symbol const & id); - - void add_axiom(expr * axiom) { - m_asts.push_back(axiom); - m_axioms.push_back(axiom); - } - - expr_iterator begin_axioms() const { - return m_axioms.begin(); - } - - unsigned get_num_axioms() const { - return m_axioms.size(); - } - - expr * const * get_axioms() const { - return m_axioms.c_ptr(); - } - - expr_iterator end_axioms() const { - return m_axioms.end(); - } - - void add_assumption(expr * axiom) { - m_asts.push_back(axiom); - m_assumptions.push_back(axiom); - } - - unsigned get_num_assumptions() const { - return m_assumptions.size(); - } - - expr * const * get_assumptions() const { - return m_assumptions.c_ptr(); - } - - bool get_func_decl(symbol, func_decl*&); - - bool get_sort(symbol, sort*&); - - bool get_const(symbol, expr*&); - - void set_name(symbol const& name) { m_name = name; } - - symbol const get_name() const { return m_name; } - protected: - symbol m_name; - ast_manager& m_ast_manager; - ptr_vector m_axioms; - ptr_vector m_assumptions; - symtable m_symtable; - ast_ref_vector m_asts; - - private: - theory& operator=(theory const&); - - theory(theory const&); - }; - - class benchmark : public theory { - public: - enum status { - UNKNOWN, - SAT, - UNSAT - }; - - benchmark(ast_manager & ast_manager, symbol const & name) : - theory(ast_manager, name), - m_status(UNKNOWN) {} - - virtual ~benchmark() {} - - status get_status() const { return m_status; } - void set_status(status status) { m_status = status; } - - symbol get_logic() const { - if (m_logic == symbol::null) { - return symbol("ALL"); - } - return m_logic; - } - - void set_logic(symbol const & s) { m_logic = s; } - - unsigned get_num_formulas() const { - return m_formulas.size(); - } - - expr_iterator begin_formulas() const { - return m_formulas.begin(); - } - - expr_iterator end_formulas() const { - return m_formulas.end(); - } - - void add_formula(expr * formula) { - m_asts.push_back(formula); - m_formulas.push_back(formula); - } - - void display_as_smt2(std::ostream & out) const; - - private: - status m_status; - symbol m_logic; - ptr_vector m_formulas; - }; -}; - -#endif diff --git a/src/parsers/smt/smtlib_solver.cpp b/src/parsers/smt/smtlib_solver.cpp deleted file mode 100644 index 339be2ddd..000000000 --- a/src/parsers/smt/smtlib_solver.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtlib_solver.cpp - -Abstract: - - SMT based solver. - -Author: - - Nikolaj Bjorner (nbjorner) 2006-11-3. - -Revision History: - ---*/ - -#include "parsers/smt/smtparser.h" -#include "parsers/smt/smtlib_solver.h" -#include "util/warning.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/well_sorted.h" -#include "model/model.h" -#include "model/model_v2_pp.h" -#include "solver/solver.h" -#include "tactic/portfolio/smt_strategic_solver.h" -#include "cmd_context/cmd_context.h" -#include "model/model_params.hpp" -#include "parsers/util/parser_params.hpp" - -namespace smtlib { - - solver::solver(): - m_ast_manager(m_params.m_proof ? PGM_ENABLED : PGM_DISABLED, - m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0), - m_ctx(0), - m_error_code(0) { - parser_params ps; - m_parser = parser::create(m_ast_manager, ps.ignore_user_patterns()); - m_parser->initialize_smtlib(); - } - - solver::~solver() { - if (m_ctx) - dealloc(m_ctx); - } - - bool solver::solve_smt(char const * benchmark_file) { - IF_VERBOSE(100, verbose_stream() << "parsing...\n";); - if (!m_parser->parse_file(benchmark_file)) { - if (benchmark_file) { - warning_msg("could not parse file '%s'.", benchmark_file); - } - else { - warning_msg("could not parse input stream."); - } - m_error_code = ERR_PARSER; - return false; - } - benchmark * benchmark = m_parser->get_benchmark(); - solve_benchmark(*benchmark); - return true; - } - - bool solver::solve_smt_string(char const * benchmark_string) { - if (!m_parser->parse_string(benchmark_string)) { - warning_msg("could not parse string '%s'.", benchmark_string); - return false; - } - benchmark * benchmark = m_parser->get_benchmark(); - solve_benchmark(*benchmark); - return true; - } - - void solver::display_statistics() { - if (m_ctx) - m_ctx->display_statistics(); - } - - void solver::solve_benchmark(benchmark & benchmark) { - if (benchmark.get_num_formulas() == 0) { - // Hack: it seems SMT-LIB allow benchmarks without any :formula - benchmark.add_formula(m_ast_manager.mk_true()); - } - m_ctx = alloc(cmd_context, true, &m_ast_manager, benchmark.get_logic()); - m_ctx->set_solver_factory(mk_smt_strategic_solver_factory()); - theory::expr_iterator fit = benchmark.begin_formulas(); - theory::expr_iterator fend = benchmark.end_formulas(); - for (; fit != fend; ++fit) - solve_formula(benchmark, *fit); - } - - void solver::solve_formula(benchmark const & benchmark, expr * f) { - IF_VERBOSE(100, verbose_stream() << "starting...\n";); - m_ctx->reset(); - for (unsigned i = 0; i < benchmark.get_num_axioms(); i++) - m_ctx->assert_expr(benchmark.get_axioms()[i]); - m_ctx->assert_expr(f); - m_ctx->check_sat(benchmark.get_num_assumptions(), benchmark.get_assumptions()); - check_sat_result * r = m_ctx->get_check_sat_result(); - if (r != 0) { - proof * pr = r->get_proof(); - if (pr != 0 && m_params.m_proof) - std::cout << mk_ll_pp(pr, m_ast_manager, false, false); - model_ref md; - if (r->status() != l_false) r->get_model(md); - if (md.get() != 0 && m_params.m_model) { - model_params p; - model_v2_pp(std::cout, *(md.get()), p.partial()); - } - } - else { - m_error_code = ERR_UNKNOWN_RESULT; - } - } -}; diff --git a/src/parsers/smt/smtlib_solver.h b/src/parsers/smt/smtlib_solver.h deleted file mode 100644 index 6288c360b..000000000 --- a/src/parsers/smt/smtlib_solver.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtlib_solver.h - -Abstract: - - SMT based solver. - -Author: - - Nikolaj Bjorner (nbjorner) 2006-11-3. - -Revision History: - ---*/ -#ifndef SMTLIB_SOLVER_H_ -#define SMTLIB_SOLVER_H_ - -#include "parsers/smt/smtparser.h" -#include "cmd_context/context_params.h" -#include "util/lbool.h" - -class cmd_context; - -namespace smtlib { - class solver { - context_params m_params; - ast_manager m_ast_manager; - cmd_context * m_ctx; - scoped_ptr m_parser; - unsigned m_error_code; - public: - solver(); - ~solver(); - bool solve_smt(char const * benchmark_file); - bool solve_smt_string(char const * benchmark_string); - void display_statistics(); - unsigned get_error_code() const { return m_error_code; } - private: - void solve_benchmark(benchmark & benchmark); - void solve_formula(benchmark const & benchmark, expr * f); - }; -}; - -#endif diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp deleted file mode 100644 index 15f094e33..000000000 --- a/src/parsers/smt/smtparser.cpp +++ /dev/null @@ -1,2760 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtparser.cpp - -Abstract: - - SMT parser into ast. - -Author: - - Nikolaj Bjorner (nbjorner) 2006-10-4. - Leonardo de Moura (leonardo) - -Revision History: ---*/ -#include -#include -#include -#include -#include -#include "util/region.h" -#include "parsers/util/scanner.h" -#include "util/symbol.h" -#include "util/vector.h" -#include "util/symbol_table.h" -#include "parsers/smt/smtlib.h" -#include "parsers/smt/smtparser.h" -#include "ast/ast_pp.h" -#include "ast/bv_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "util/warning.h" -#include "util/error_codes.h" -#include "parsers/util/pattern_validation.h" -#include "ast/rewriter/var_subst.h" -#include "ast/well_sorted.h" -#include "util/str_hashtable.h" -#include "util/stopwatch.h" - -class id_param_info { - symbol m_string; - unsigned m_num_params; - parameter m_params[0]; -public: - id_param_info(symbol const& s, unsigned n, parameter const* p) : m_string(s), m_num_params(n) { - for (unsigned i = 0; i < n; ++i) { - new (&(m_params[i])) parameter(); - m_params[i] = p[i]; - } - } - symbol string() const { return m_string; } - parameter * params() { return m_params; } - unsigned num_params() const { return m_num_params; } -}; - -class proto_region { - ptr_vector m_rationals; - ptr_vector m_id_infos; - region m_region; -public: - proto_region() { } - - ~proto_region() { reset(); } - - rational* allocate(rational const & n) { - rational* r = alloc(rational, n); - m_rationals.push_back(r); - return r; - } - - id_param_info* allocate(vector const& params, symbol const & s) { - unsigned size = sizeof(id_param_info) + sizeof(parameter)*(params.size()); - id_param_info* r = static_cast(m_region.allocate(size)); - new (r) id_param_info(s, params.size(), params.c_ptr()); - m_id_infos.push_back(r); - return r; - } - - void* allocate(size_t s) { return m_region.allocate(s); } - - void reset() { - for (unsigned i = 0; i < m_rationals.size(); ++i) { - dealloc(m_rationals[i]); - } - for (unsigned i = 0; i < m_id_infos.size(); ++i) { - unsigned n = m_id_infos[i]->num_params(); - for (unsigned j = 0; j < n; ++j) { - m_id_infos[i]->params()[j].~parameter(); - } - } - m_rationals.reset(); - m_id_infos.reset(); - m_region.reset(); - } - -private: - -}; - -inline void * operator new(size_t s, proto_region& r) { return r.allocate(s); } -inline void * operator new[](size_t s, proto_region & r) { return r.allocate(s); } -inline void operator delete(void*, proto_region& r) {} -inline void operator delete[](void *, proto_region& r) {} - -class proto_expr { -public: - - enum kind_t { - ID, - STRING, - COMMENT, - ANNOTATION, - INT, - FLOAT, - CONS - }; -private: - - int m_kind:8; - int m_line:24; - int m_pos; - union { - id_param_info* m_id_info; - rational* m_number; - proto_expr** m_children; - }; - -public: - - symbol string() { - if (m_kind == INT || m_kind == FLOAT) { - std::string s = m_number->to_string(); - return symbol(s.c_str()); - } - if (m_kind == CONS) { - return symbol(""); - } - SASSERT(m_kind == STRING || m_kind == COMMENT || m_kind == ID || m_kind == ANNOTATION); - return m_id_info->string(); - } - - rational const& number() { - SASSERT(m_kind == INT || m_kind == FLOAT); - return *m_number; - } - - proto_expr* const* children() const { - if (m_kind == CONS) { - return m_children; - } - else { - return 0; - } - } - - int line() { return m_line; } - int pos() { return m_pos; } - kind_t kind() { return static_cast(m_kind); } - - unsigned num_params() const { - SASSERT(m_kind == ID); - return m_id_info->num_params(); - } - - parameter * params() { - SASSERT(m_kind == ID); - return m_id_info->params(); - } - - proto_expr(proto_region & region, kind_t kind, symbol const & s, vector const & params, int line, int pos): - m_kind(kind), - m_line(line), - m_pos(pos), - m_id_info(region.allocate(params, s)) { - SASSERT(kind != CONS); - SASSERT(kind != INT); - SASSERT(kind != FLOAT); - } - - proto_expr(proto_region& region, bool is_int, rational const & n, int line, int pos): - m_kind(is_int?INT:FLOAT), - m_line(line), - m_pos(pos), - m_number(region.allocate(n)) - {} - - proto_expr(proto_region& region, ptr_vector& proto_exprs, int line, int pos): - m_kind(CONS), - m_line(line), - m_pos(pos) { - // - // null terminated list of proto_expression pointers. - // - unsigned num_children = proto_exprs.size(); - m_children = new (region) proto_expr*[num_children+1]; - for (unsigned i = 0; i < num_children; ++i) { - m_children[i] = proto_exprs[i]; - } - m_children[num_children] = 0; - } - - ~proto_expr() {} - - - static proto_expr* copy(proto_region& r, proto_expr* e) { - switch(e->kind()) { - case proto_expr::CONS: { - ptr_vector args; - proto_expr* const* children = e->children(); - while (children && *children) { - args.push_back(copy(r, *children)); - ++children; - } - return new (r) proto_expr(r, args, e->line(), e->pos()); - } - case proto_expr::INT: { - return new (r) proto_expr(r, true, e->number(), e->line(), e->pos()); - } - case proto_expr::FLOAT: { - return new (r) proto_expr(r, false, e->number(), e->line(), e->pos()); - } - case proto_expr::ID: { - vector params; - for (unsigned i = 0; i < e->num_params(); ++i) { - params.push_back(e->params()[i]); - } - return new (r) proto_expr(r, e->kind(), e->string(), params, e->line(), e->pos()); - } - default: { - vector params; - return new (r) proto_expr(r, e->kind(), e->string(), params, e->line(), e->pos()); - } - } - } - -private: - - proto_expr(proto_expr const & other); - proto_expr& operator=(proto_expr const & other); -}; - - -// -// build up proto_expr tree from token stream. -// - -class proto_expr_parser { - proto_region& m_region; - scanner& m_scanner; - std::ostream& m_err; - bool m_at_eof; -public: - proto_expr_parser(proto_region& region, scanner& scanner, std::ostream& err): - m_region(region), - m_scanner(scanner), - m_err(err), - m_at_eof(false) { - } - - ~proto_expr_parser() {} - - bool parse(ptr_vector & proto_exprs, bool parse_single_expr = false) { - scanner::token token; - vector stack; - proto_expr* result = 0; - - stack.push_back(frame(PROTO_EXPRS_PRE)); - - token = m_scanner.scan(); - - if (token == scanner::EOF_TOKEN) { - proto_exprs.reset(); - return true; - } - - while (!stack.empty()) { - - if (token == scanner::EOF_TOKEN) { - break; - } - - if (token == scanner::ERROR_TOKEN) { - print_error("unexpected token"); - goto done; - } - - switch(stack.back().m_state) { - - case PROTO_EXPR: - switch (token) { - case scanner::LEFT_PAREN: - stack.back().m_state = PROTO_EXPRS_PRE; - token = m_scanner.scan(); - break; - default: - stack.back().m_state = ATOM; - break; - } - break; - - case ATOM: - SASSERT(!result); - switch(token) { - case scanner::ID_TOKEN: - result = new (m_region) proto_expr(m_region, proto_expr::ID, m_scanner.get_id(), m_scanner.get_params(), - m_scanner.get_line(), m_scanner.get_pos()); - break; - case scanner::INT_TOKEN: - result = new (m_region) proto_expr(m_region, true, m_scanner.get_number(), m_scanner.get_line(), - m_scanner.get_pos()); - break; - case scanner::FLOAT_TOKEN: - result = new (m_region) proto_expr(m_region, false, m_scanner.get_number(), m_scanner.get_line(), - m_scanner.get_pos()); - break; - case scanner::STRING_TOKEN: - result = new (m_region) proto_expr(m_region, proto_expr::STRING, m_scanner.get_id(), m_scanner.get_params(), - m_scanner.get_line(), m_scanner.get_pos()); - break; - case scanner::COMMENT_TOKEN: - result = new (m_region) proto_expr(m_region, proto_expr::COMMENT, m_scanner.get_id(), m_scanner.get_params(), - m_scanner.get_line(), m_scanner.get_pos()); - break; - case scanner::COLON: - token = m_scanner.scan(); - if (token == scanner::ID_TOKEN) { - result = new (m_region) proto_expr(m_region, proto_expr::ANNOTATION, m_scanner.get_id(), - m_scanner.get_params(), m_scanner.get_line(), m_scanner.get_pos()); - } - else { - print_error("unexpected identifier ':'"); - token = scanner::ERROR_TOKEN; - goto done; - } - break; - default: - print_error("unexpected token"); - token = scanner::ERROR_TOKEN; - goto done; - } - stack.pop_back(); - SASSERT(!stack.empty()); - stack.back().m_proto_exprs.push_back(result); - result = 0; - if (parse_single_expr && stack.size() == 1) { - goto done; - } - token = m_scanner.scan(); - break; - - case PROTO_EXPRS_PRE: - SASSERT(!result); - switch(token) { - case scanner::RIGHT_PAREN: - result = new (m_region) proto_expr(m_region, stack.back().m_proto_exprs, m_scanner.get_line(), - m_scanner.get_pos()); - stack.pop_back(); - - if (stack.empty()) { - print_error("unexpected right parenthesis"); - token = scanner::ERROR_TOKEN; - result = 0; - goto done; - } - stack.back().m_proto_exprs.push_back(result); - if (parse_single_expr && stack.size() == 1) { - goto done; - } - result = 0; - token = m_scanner.scan(); - break; - - case scanner::EOF_TOKEN: - m_at_eof = true; - break; - - case scanner::ERROR_TOKEN: - print_error("could not parse expression"); - goto done; - - default: - stack.back().m_state = PROTO_EXPRS_POST; - stack.push_back(frame(PROTO_EXPR)); - break; - } - break; - - case PROTO_EXPRS_POST: - stack.back().m_state = PROTO_EXPRS_PRE; - break; - } - } - - done: - - if (stack.size() == 1) { - for (unsigned i = 0; i < stack.back().m_proto_exprs.size(); ++i) { - proto_exprs.push_back(stack.back().m_proto_exprs[i]); - } - return true; - } - - if (stack.size() == 2) { - proto_exprs.push_back(new (m_region) proto_expr(m_region, stack.back().m_proto_exprs, m_scanner.get_line(), - m_scanner.get_pos())); - return true; - } - - print_error("unexpected nesting of parenthesis: ", stack.size()); - return false; - } - - int get_line() { - return m_scanner.get_line(); - } - - bool at_eof() const { - return m_at_eof; - } - -private: - - template - void print_error(char const* msg1, T msg2) { - m_err << "ERROR: line " << m_scanner.get_line() - << " column " << m_scanner.get_pos() << ": " - << msg1 << msg2 << "\n"; - } - - void print_error(char const* msg) { - print_error(msg, ""); - } - - // stack frame: - enum frame_state { - PROTO_EXPR, - PROTO_EXPRS_PRE, - PROTO_EXPRS_POST, - ATOM - }; - - class frame { - public: - frame_state m_state; - ptr_vector m_proto_exprs; - frame(frame_state state): - m_state(state){ - } - frame(frame const & other): - m_state(other.m_state), - m_proto_exprs(other.m_proto_exprs) { - } - private: - frame& operator=(frame const &); - }; - -}; - -using namespace smtlib; - -class idbuilder { -public: - virtual ~idbuilder() {} - virtual bool apply(expr_ref_vector const & args, expr_ref & result) = 0; -}; - -class builtin_sort_builder : public sort_builder { - ast_manager& m_manager; - family_id m_fid; - decl_kind m_kind; -public: - builtin_sort_builder(ast_manager& m, family_id fid, decl_kind k) : - m_manager(m), m_fid(fid), m_kind(k) {} - - virtual bool apply(unsigned num_params, parameter const* params, sort_ref & result) { - result = m_manager.mk_sort(m_fid, m_kind, num_params, params); - return result.get() != 0; - } -}; - -class array_sort : public builtin_sort_builder { -public: - array_sort(ast_manager& m) : - builtin_sort_builder(m, m.mk_family_id("array"), ARRAY_SORT) {} -}; - -class bv_sort : public builtin_sort_builder { -public: - bv_sort(ast_manager& m) : - builtin_sort_builder(m, m.mk_family_id("bv"), BV_SORT) {} -}; - -class user_sort : public sort_builder { - user_sort_plugin * m_plugin; - decl_kind m_kind; - symbol m_name; - unsigned m_num_args; - std::string m_error_message; -public: - user_sort(ast_manager& m, unsigned num_args, symbol name): - m_name(name), - m_num_args(num_args) { - m_plugin = m.get_user_sort_plugin(); - m_kind = m_plugin->register_name(name); - } - - ~user_sort() {} - - virtual bool apply(unsigned num_params, parameter const* params, sort_ref & result) { - if (num_params != m_num_args) { - std::ostringstream strm; - strm << "wrong number of arguments passed to " << m_name << " " - << m_num_args << " expected, but " << num_params << " given"; - m_error_message = strm.str(); - return false; - } - result = m_plugin->mk_sort(m_kind, num_params, params); - return true; - } - - virtual char const* error_message() { - return m_error_message.c_str(); - } -}; - -class smtparser : public parser { - struct builtin_op { - family_id m_family_id; - decl_kind m_kind; - builtin_op() : m_family_id(null_family_id), m_kind(0) {} - builtin_op(family_id fid, decl_kind k) : m_family_id(fid), m_kind(k) {} - }; - - class add_plugins { - - public: - add_plugins(ast_manager& m) { -#define REGISTER_PLUGIN(NAME, MK) { \ - family_id fid = m.mk_family_id(symbol(NAME)); \ - if (!m.has_plugin(fid)) { \ - m.register_plugin(fid, MK); \ - } \ - } ((void) 0) - - REGISTER_PLUGIN("arith", alloc(arith_decl_plugin)); - REGISTER_PLUGIN("bv", alloc(bv_decl_plugin)); - REGISTER_PLUGIN("array", alloc(array_decl_plugin)); - - }; - }; - - ast_manager& m_manager; - add_plugins m_plugins; - arith_util m_anum_util; - bv_util m_bvnum_util; - pattern_validator m_pattern_validator; - bool m_ignore_user_patterns; - unsigned m_binding_level; // scope level for bound vars - benchmark m_benchmark; // currently parsed benchmark - - typedef map op_map; - op_map m_builtin_ops; - op_map m_builtin_sorts; - - symbol m_let; // commonly used symbols. - symbol m_flet; - symbol m_forall; - symbol m_exists; - symbol m_lblneg; - symbol m_lblpos; - symbol m_associative; - symbol m_commutative; - symbol m_injective; - symbol m_sorts; - symbol m_funs; - symbol m_preds; - symbol m_axioms; - symbol m_notes; - symbol m_array; - symbol m_bang; - symbol m_underscore; - sort* m_int_sort; - sort* m_real_sort; - family_id m_bv_fid; - family_id m_arith_fid; - family_id m_array_fid; - family_id m_rel_fid; - func_decl * m_sk_hack; - std::ostream* m_err; - bool m_display_error_for_vs; - - -public: - - smtparser(ast_manager& m, bool ignore_user_patterns): - m_manager(m), - m_plugins(m), - m_anum_util(m), - m_bvnum_util(m), - m_pattern_validator(m), - m_ignore_user_patterns(ignore_user_patterns), - m_binding_level(0), - m_benchmark(m_manager, symbol("")), - m_let("let"), - m_flet("flet"), - m_forall("forall"), - m_exists("exists"), - m_lblneg("lblneg"), - m_lblpos("lblpos"), - m_associative("assoc"), - m_commutative("comm"), - m_injective("injective"), - m_sorts("sorts"), - m_funs("funs"), - m_preds("preds"), - m_axioms("axioms"), - m_notes("notes"), - m_array("array"), - m_bang("!"), - m_underscore("_"), - m_err(0), - m_display_error_for_vs(false) - { - family_id bfid = m_manager.get_basic_family_id(); - - add_builtin_type("bool", bfid, BOOL_SORT); - m_benchmark.get_symtable()->insert(symbol("Array"), alloc(array_sort, m)); - m_benchmark.get_symtable()->insert(symbol("BitVec"), alloc(bv_sort, m)); - - - add_builtins(bfid); - } - - ~smtparser() { - } - - void set_error_stream(std::ostream& strm) { m_err = &strm; } - - std::ostream& get_err() { return m_err?(*m_err):std::cerr; } - - bool ignore_user_patterns() const { return m_ignore_user_patterns; } - - bool parse_stream(std::istream& stream) { - proto_region region; - scanner scanner(stream, get_err(), false); - proto_expr_parser parser(region, scanner, get_err()); - return parse(parser); - } - - bool parse_file(char const * filename) { - if (filename != 0) { - std::ifstream stream(filename); - if (!stream) { - get_err() << "ERROR: could not open file '" << filename << "'.\n"; - return false; - } - return parse_stream(stream); - } - else { - return parse_stream(std::cin); - } - } - - bool parse_string(char const * str) { - std::string s = str; - std::istringstream is(s); - return parse_stream(is); - } - - void add_builtin_op(char const * s, family_id fid, decl_kind k) { - m_builtin_ops.insert(symbol(s), builtin_op(fid, k)); - } - - void add_builtin_type(char const * s, family_id fid, decl_kind k) { - m_builtin_sorts.insert(symbol(s), builtin_op(fid, k)); - } - - void initialize_smtlib() { - smtlib::symtable* table = m_benchmark.get_symtable(); - - symbol arith("arith"); - family_id afid = m_manager.mk_family_id(arith); - m_arith_fid = afid; - - add_builtin_type("Int", afid, INT_SORT); - add_builtin_type("Real", afid, REAL_SORT); - add_builtin_type("Bool", m_manager.get_basic_family_id(), BOOL_SORT); - - m_int_sort = m_manager.mk_sort(m_arith_fid, INT_SORT); - m_real_sort = m_manager.mk_sort(m_arith_fid, REAL_SORT); - - add_builtins(afid); - - symbol bv("bv"); - family_id bfid = m_manager.mk_family_id(bv); - m_bv_fid = bfid; - - add_builtins(bfid); - - add_builtin_type("BitVec", bfid, BV_SORT); - - symbol array("array"); - afid = m_manager.mk_family_id(array); - m_array_fid = afid; - - add_builtins(afid); - - sort* a1, *a2; - func_decl* store1, *sel1, *store2, *sel2; - - // Array - parameter params0[2] = { parameter(m_int_sort), parameter(m_int_sort) }; - a1 = m_manager.mk_sort(afid, ARRAY_SORT, 2, params0); - table->insert(symbol("Array"), a1); - parameter param0(a1); - sort * args0[3] = { a1, m_int_sort, m_int_sort }; - store1 = m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, args0); - table->insert(symbol("store"), store1); - sel1 = m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, args0); - table->insert(symbol("select"), sel1); - - // Array1 - parameter params1[2] = { parameter(m_int_sort), parameter(m_real_sort) }; - a1 = m_manager.mk_sort(afid, ARRAY_SORT, 2, params1); - table->insert(symbol("Array1"), a1); - parameter param1(a1); - sort * args1[3] = { a1, m_int_sort, m_real_sort }; - store1 = m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, args1); - table->insert(symbol("store"), store1); - sel1 = m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, args1); - table->insert(symbol("select"), sel1); - - // Array2 - parameter params2[2] = { parameter(m_int_sort), parameter(a1) }; - a2 = m_manager.mk_sort(afid, ARRAY_SORT, 2, params2); - table->insert(symbol("Array2"), a2); - parameter param2(a2); - sort * args2[3] = { a2, m_int_sort, a1 }; - store2 = m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, args2); - table->insert(symbol("store"), store2); - sel2 = m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, args2); - table->insert(symbol("select"), sel2); - - m_benchmark.declare_sort(symbol("U")); - - sort * bool_sort = m_manager.mk_bool_sort(); - m_sk_hack = m_manager.mk_func_decl(symbol("sk_hack"), 1, &bool_sort, bool_sort); - table->insert(symbol("sk_hack"), m_sk_hack); - } - - - void add_builtins(family_id fid) { - decl_plugin * plugin = m_manager.get_plugin(fid); - SASSERT(plugin); - svector op_names; - plugin->get_op_names(op_names); - for (unsigned i = 0; i < op_names.size(); ++i) { - add_builtin_op(op_names[i].m_name.bare_str(), fid, op_names[i].m_kind); - } - } - - smtlib::benchmark* get_benchmark() { return &m_benchmark; } - -private: - - - bool parse(proto_expr_parser& parser) { - symbol benchmark("benchmark"); - symbol name(""); - proto_expr* const* rest = 0; - ptr_vector proto_exprs; - bool result = parser.parse(proto_exprs); - proto_expr* proto_expr = 0; - - if (!result) { - get_err() << "ERROR: parse error at line " << parser.get_line() << ".\n"; - } - - for (unsigned i = 0; result && i < proto_exprs.size(); ++i) { - - proto_expr = proto_exprs[i]; - - if (match_cons(proto_expr, benchmark, name, rest)) { - result = make_benchmark(name, rest); - } - else if (proto_expr && proto_expr->kind() != proto_expr::COMMENT) { - set_error("could not match expression to benchmark ", proto_expr); - } - else { - // proto_expr->kind() == proto_expr::COMMENT. - } - } - return result; - } - - void error_prefix(proto_expr* e) { - if (m_display_error_for_vs) { - if (e) { - get_err() << "Z3(" << e->line() << "," << e->pos() << "): ERROR: "; - } - } - else { - get_err() << "ERROR: "; - if (e) { - get_err() << "line " << e->line() << " column " << e->pos() << ": "; - } - } - } - - void set_error(char const * str, proto_expr* e) { - error_prefix(e); - if (e->kind() == proto_expr::ID) { - get_err() << str << " '" << e->string() << "'.\n"; - } - else { - get_err() << str << ".\n"; - } - } - - template - void set_error(T1 str1, T2 str2, proto_expr* e) { - error_prefix(e); - get_err() << str1 << " " << str2 << ".\n"; - } - - template - void set_error(T1 str1, T2 str2, T3 str3, proto_expr* e) { - error_prefix(e); - get_err() << str1 << str2 << str3 << ".\n"; - } - - bool match_cons(proto_expr * e, symbol const & sym, symbol & name, proto_expr* const*& proto_exprs) { - if (e && - e->kind() == proto_expr::CONS && - e->children() && - e->children()[0] && - e->children()[0]->string() == sym && - e->children()[1]) { - proto_exprs = e->children() + 2; - name = e->children()[1]->string(); - return true; - } - - return false; - } - - bool make_benchmark(symbol & name, proto_expr * const* proto_exprs) { - symbol extrasorts("extrasorts"); - symbol extrafuns("extrafuns"); - symbol extrapreds("extrapreds"); - symbol assumption("assumption"); - symbol assumption_core("assumption-core"); - symbol define_sorts_sym("define_sorts"); - symbol logic("logic"); - symbol formula("formula"); - symbol status("status"); - symbol sat("sat"); - symbol unsat("unsat"); - symbol unknown("unknown"); - symbol empty(""); - symbol source("source"); - symbol difficulty("difficulty"); - symbol category("category"); - bool success = true; - - push_benchmark(name); - - while (proto_exprs && *proto_exprs) { - proto_expr* e = *proto_exprs; - ++proto_exprs; - proto_expr* e1 = *proto_exprs; - - if (logic == e->string() && e1) { - name = e1->string(); - m_benchmark.set_logic(name); - - set_default_num_sort(name); - - if (name == symbol("QF_AX")) { - // Hack for supporting new QF_AX theory... - sort * index = m_manager.mk_uninterpreted_sort(symbol("Index")); - sort * element = m_manager.mk_uninterpreted_sort(symbol("Element")); - parameter params[2] = { parameter(index), parameter(element) }; - sort * array = m_manager.mk_sort(m_array_fid, ARRAY_SORT, 2, params); - smtlib::symtable* table = m_benchmark.get_symtable(); - table->insert(symbol("Index"), index); - table->insert(symbol("Element"), element); - // overwrite Array definition... - table->insert(symbol("Array"), array); - sort * args[3] = { array, index, element }; - func_decl * store = m_manager.mk_func_decl(m_array_fid, OP_STORE, 0, 0, 3, args); - table->insert(symbol("store"), store); - func_decl * sel = m_manager.mk_func_decl(m_array_fid, OP_SELECT, 0, 0, 2, args); - table->insert(symbol("select"), sel); - } - - ++proto_exprs; - continue; - } - - if (assumption == e->string() && e1) { - expr_ref t(m_manager); - if (!make_expression(e1, t) || - !push_assumption(t.get())) { - return false; - } - ++proto_exprs; - continue; - } - - if (assumption_core == e->string() && e1) { - expr_ref t(m_manager); - if (!make_expression(e1, t)) - return false; - m_benchmark.add_assumption(t.get()); - ++proto_exprs; - continue; - } - - if (define_sorts_sym == e->string() && e1) { - if (!define_sorts(e1)) { - return false; - } - ++proto_exprs; - continue; - } - - if (formula == e->string() && e1) { - expr_ref t(m_manager); - if (!make_expression(e1, t) || - !push_formula(t.get())) { - return false; - } - ++proto_exprs; - continue; - } - - if (status == e->string() && e1) { - if (sat == e1->string()) { - if (!push_status(smtlib::benchmark::SAT)) { - set_error("could not push status ", e1->string(),e1); - return false; - } - } - else if (unsat == e1->string()) { - if (!push_status(smtlib::benchmark::UNSAT)) { - set_error("could not push status ", e1->string(),e1); - return false; - } - } - else if (unknown == e1->string()) { - if (!push_status(smtlib::benchmark::UNKNOWN)) { - set_error("could not push status ", e1->string(),e1); - return false; - } - } - else { - set_error("could not recognize status ", e1->string(),e1); - return false; - } - ++proto_exprs; - continue; - } - - if (extrasorts == e->string() && e1) { - if (!declare_sorts(e1)) { - return false; - } - ++proto_exprs; - continue; - } - if (extrafuns == e->string() && e1) { - if (!declare_funs(e1)) { - return false; - } - ++proto_exprs; - continue; - } - if (extrapreds == e->string() && e1) { - if (!declare_preds(e1)) { - return false; - } - ++proto_exprs; - continue; - } - if (m_notes == e->string() && e1) { - ++proto_exprs; - continue; - } - - if ((source == e->string() || difficulty == e->string() || category == e->string()) && e1) { - ++proto_exprs; - continue; - } - - if (e->string() != empty) { - set_error("ignoring unknown attribute '", e->string().bare_str(), "'", e); - if (e1) { - ++proto_exprs; - } - // do not fail. - // success = false; - continue; - } - - TRACE("smtparser", - tout << "skipping: " << e->string() << " " << - e->line() << " " << - e->pos() << ".\n";); - continue; - } - return success; - } - - bool is_id_token(proto_expr* expr) { - return - expr && - (expr->kind() == proto_expr::ID || - expr->kind() == proto_expr::STRING || - expr->kind() == proto_expr::ANNOTATION); - } - - bool check_id(proto_expr* e) { - return is_id_token(e); - } - - bool make_expression(proto_expr * e, expr_ref & result) { - m_binding_level = 0; - symbol_table local_scope; - return make_expression(local_scope, e, result); - } - - bool make_func_decl(proto_expr* e, func_decl_ref& result) { - func_decl* f; - if (m_benchmark.get_symtable()->find1(e->string(), f)) { - result = f; - return true; - } - else { - return false; - } - } - - bool make_bool_expression(symbol_table& local_scope, proto_expr * e, expr_ref & result) { - if (!make_expression(local_scope, e, result)) { - return false; - } - if (!m_manager.is_bool(result)) { - set_error("expecting Boolean expression", e); - return false; - } - return true; - } - - bool make_bool_expressions(symbol_table& local_scope, proto_expr * const* chs, expr_ref_vector & exprs) { - while (chs && *chs) { - expr_ref result(m_manager); - m_binding_level = 0; - if (!make_bool_expression(local_scope, *chs, result)) { - return false; - } - exprs.push_back(result); - ++chs; - } - return true; - } - - bool make_expression(symbol_table& local_scope, proto_expr * e, expr_ref & result) { - // - // Walk proto_expr by using the zipper. - // That is, maintain a stack of what's - // . left - already processed. - // . right - to be processed. - // . up - above the processed node. - // - - region region; - - expr_ref_vector * left = alloc(expr_ref_vector, m_manager); - proto_expr* const* right = 0; - ptr_vector up; - proto_expr* current = e; - bool success = false; - idbuilder* builder = 0; - - while (true) { - - if (!current && right && *right) { - // - // pull the current from right. - // - current = *right; - ++right; - } - - if (!current && up.empty()) { - // - // we are done. - // - if (left->size() == 0) { - // set_error(); - set_error("there are no expressions to return", e); - goto cleanup; - } - if (left->size() != 1) { - set_error("there are too many expressions to return", e); - goto cleanup; - } - result = left->back(); - success = true; - goto cleanup; - } - - if (!current && !up.empty()) { - // - // There is nothing more to process at this level. - // - // Apply the operator on the stack to the - // current 'left' vector. - // Adjust the stack by popping the left and right - // work-lists. - // - expr_ref term(m_manager); - parse_frame* above = up.back(); - // symbol sym = above->get_proto_expr()->string(); - - if (above->make_term()) { - if (!above->make_term()->apply(*left, term)) { - set_error("Could not create application", - above->get_proto_expr()); - success = false; - goto cleanup; - } - } - else if (!make_app(above->get_proto_expr(), *left, term)) { - success = false; - goto cleanup; - } - dealloc(left); - left = above->detach_left(); - left->push_back(term.get()); - right = above->right(); - m_binding_level = above->binding_level(); - up.pop_back(); - continue; - } - - while (current && - current->kind() == proto_expr::CONS && - current->children() && - current->children()[0] && - !current->children()[1]) { - current = current->children()[0]; - } - - switch(current->kind()) { - - case proto_expr::ANNOTATION: - // ignore - current = 0; - break; - - case proto_expr::ID: { - symbol const& id = current->string(); - expr_ref term(m_manager); - expr * const_term = 0; - bool ok = true; - - if (local_scope.find(id, builder)) { - expr_ref_vector tmp(m_manager); - if (!builder->apply(tmp, term)) { - set_error("identifier supplied with the wrong number of arguments ", id, current); - goto cleanup; - - } - } - else if (m_benchmark.get_const(id, const_term)) { - // found. - term = const_term; - } - else if (is_builtin_const(id, current, current->num_params(), current->params(), ok, term)) { - if (!ok) goto cleanup; - } - else if (is_bvconst(id, current->num_params(), current->params(), term)) { - // found - } - else { - set_error("could not locate id ", id, current); - goto cleanup; - } - - left->push_back(term.get()); - current = 0; - break; - } - - case proto_expr::STRING: - // - // Ignore strings. - // - current = 0; - break; - - case proto_expr::COMMENT: - // - // Ignore comments. - // - current = 0; - break; - - case proto_expr::INT: - - left->push_back(mk_number(current->number(), true)); - current = 0; - break; - - case proto_expr::FLOAT: - left->push_back(mk_number(current->number(), false)); - current = 0; - break; - - case proto_expr::CONS: - - if (!current->children() || - !current->children()[0]) { - set_error("cons does not have children", current); - current = 0; - goto cleanup; - } - - // - // expect the head to be a symbol - // which can be used to build a term of - // the subterms. - // - - symbol const& head_symbol = current->children()[0]->string(); - - if (head_symbol == m_underscore) { - - expr_ref term(m_manager); - - proto_expr * const* chs = current->children() + 1; - symbol const& id = chs[0]->string(); - sort_ref_vector sorts(m_manager); - vector params; - bool ok = true; - if (!parse_params(chs+1, params, sorts)) { - goto cleanup; - } - if (is_builtin_const(id, current, params.size(), params.c_ptr(), ok, term)) { - if (!ok) goto cleanup; - } - else if (is_bvconst(id, params.size(), params.c_ptr(), term)) { - // ok - } - else { - set_error("Could not parse _ term", current); - goto cleanup; - } - left->push_back(term.get()); - current = 0; - break; - } - - if ((head_symbol == m_let) || - (head_symbol == m_flet)) { - - if (!current->children()[1] || - !current->children()[2]) { - set_error("let does not have two arguments", current); - goto cleanup; - } - - proto_expr * let_binding = current->children()[1]; - proto_expr * const* let_body = current->children()+2; - - // - // Collect bound variables and definitions for the bound variables - // into vectors 'vars' and 'bound'. - // - svector vars; - ptr_vector bound_vec; - if (is_binary_let_binding(let_binding)) { - vars.push_back(let_binding->children()[0]->string()); - bound_vec.push_back(let_binding->children()[1]); - } - else { - proto_expr* const* children = let_binding->children(); - if (!children) { - set_error("let binding does not have two arguments", let_binding); - goto cleanup; - } - while (*children) { - proto_expr* ch = *children; - if (!is_binary_let_binding(ch)) { - set_error("let binding does not have two arguments", ch); - goto cleanup; - } - vars.push_back(ch->children()[0]->string()); - bound_vec.push_back(ch->children()[1]); - ++children; - } - } - bound_vec.push_back(0); - - proto_expr** bound = new (region) proto_expr*[bound_vec.size()]; - for (unsigned i = 0; i < bound_vec.size(); ++i) { - bound[i] = bound_vec[i]; - } - - // - // Let's justify the transformation that - // pushes push_let and pop_let on the stack. - // and how it processes the let declaration. - // - // walk up left ((let ((v1 x1) (v2 x2)) z)::right) - // - // = - // - // walk (up::(pop_let(),left,right)::(bind(v1,v2),[],[z])) [] [x1;x2] - // - // = (* assume x1 -> y1, x2 -> y2 *) - // - // walk (up::(pop_let(),left,right)::(bind(v1,v2),[],[z])) [y1;y2] [] - // - // = (* apply binding *) - // - // walk (up::(pop_let(),left,right)) [] [z] - // - // = (* assume z -> u *) - // - // walk up {left::u] right - // - // so if pop_let(v) [a,b] has the effect of removing v from the environment - // and projecting the second element "b", we obtain the effect of a let-binding. - // - - expr_ref_vector * pinned = alloc(expr_ref_vector, m_manager); - pop_let * popl = new (region) pop_let(local_scope, pinned); - up.push_back(new (region) parse_frame(let_binding, popl, left, right, m_binding_level)); - - - push_let_and * pushl = new (region) push_let_and(this, region, local_scope, pinned, vars.size(), vars.c_ptr()); - expr_ref_vector * tmp = alloc(expr_ref_vector, m_manager); - up.push_back(new (region) parse_frame(let_binding, pushl, tmp, let_body, m_binding_level)); - - - left = alloc(expr_ref_vector, m_manager); - right = bound; - current = 0; - break; - } - - if (head_symbol == m_lblneg || - head_symbol == m_lblpos) { - if (!current->children()[1] || - !current->children()[2]) { - set_error("labels require two arguments", current); - goto cleanup; - } - - bool is_pos = head_symbol == m_lblpos; - idbuilder* lbl = new (region) build_label(this, is_pos, current->children()[1]); - - up.push_back(new (region) parse_frame(current, lbl, left, right, m_binding_level)); - - // - // process the body. - // - left = alloc(expr_ref_vector, m_manager); - right = 0; - current = current->children()[2]; - break; - } - - if (head_symbol == m_bang) { - proto_expr* const* children = current->children(); - proto_expr* body = children[1]; - proto_expr* lblname = 0; - bool is_pos = false; - - children += 2; - - while (children[0] && - children[0]->kind() == proto_expr::ANNOTATION && - children[1]) { - symbol id = children[0]->string(); - - if ((id == m_lblneg) || - (id == m_lblpos)) { - is_pos = id == m_lblpos; - lblname = children[1]; - } - - children += 2; - } - - if (lblname) { - idbuilder* lbl = new (region) build_label(this, is_pos, lblname); - up.push_back(new (region) parse_frame(current, lbl, left, right, m_binding_level)); - left = alloc(expr_ref_vector, m_manager); - right = 0; - } - - // - // process the body. - // - current = body; - break; - } - - if ((head_symbol == m_forall) || - (head_symbol == m_exists)) { - - expr_ref_buffer patterns(m_manager); - expr_ref_buffer no_patterns(m_manager); - sort_ref_buffer sorts(m_manager); - svector vars; - int weight = 1; - - proto_expr* const* children = current->children(); - proto_expr* body = 0; - - ++children; - - if (!children[0] || !children[1]) { - set_error("quantifier should have at least two arguments", current); - goto cleanup; - } - - // - // restore 'left' and 'right' working set and m_binding_level. - // - up.push_back(new (region) parse_frame(current, new (region) identity(), left, right, m_binding_level)); - left = alloc(expr_ref_vector, m_manager); - - // - // declare the bound variables. - // - - local_scope.begin_scope(); - - while (children[0] && children[1] && - (children[1]->kind() != proto_expr::ANNOTATION)) { - - if (!parse_bound(local_scope, region, *children, vars, sorts)) { - goto cleanup; - } - ++children; - } - - body = children[0]; - - if (is_annotated_cons(body)) { - children = body->children()+1; - body = body->children()[1]; - } - - ++children; - - symbol qid = symbol(current->line()); - symbol skid = symbol(); - - read_patterns(vars.size(), local_scope, children, patterns, no_patterns, weight, qid, skid); - - // - // push a parse_frame to undo the scope of the quantifier. - // - - SASSERT(sorts.size() > 0); - - idbuilder* pop_q = new (region) pop_quantifier(this, (head_symbol == m_forall), weight, qid, skid, patterns, no_patterns, sorts, vars, local_scope); - - expr_ref_vector * empty_v = alloc(expr_ref_vector, m_manager); - up.push_back(new (region) parse_frame(current, pop_q, empty_v, 0, m_binding_level)); - - // - // process the body. - // - right = 0; - current = body; - break; - } - - if (is_underscore_op(region, current->children()[0], builder)) { - up.push_back(new (region) parse_frame(current, builder, left, right, m_binding_level)); - } - else if (local_scope.find(head_symbol, builder)) { - up.push_back(new (region) parse_frame(current, builder, left, right, m_binding_level)); - } - else { - up.push_back(new (region) parse_frame(current->children()[0], left, right, m_binding_level)); - } - left = alloc(expr_ref_vector, m_manager); - right = current->children() + 1; - current = 0; - break; - } - } - - cleanup: - - if (success && !is_well_sorted(m_manager, result)) { - set_error("expression is not well sorted", e); - success = false; - } - - dealloc(left); - while (!up.empty()) { - dealloc(up.back()->detach_left()); - up.pop_back(); - } - return success; - } - - bool read_patterns(unsigned num_bindings, symbol_table & local_scope, proto_expr * const * & children, - expr_ref_buffer & patterns, expr_ref_buffer & no_patterns, int& weight, symbol& qid, symbol& skid) { - proto_region region; - while (children[0] && - children[0]->kind() == proto_expr::ANNOTATION && - children[1]) { - - if (children[0]->string() == symbol("qid") || - children[0]->string() == symbol("named")) { - qid = children[1]->string(); - children += 2; - continue; - } - - if (children[0]->string() == symbol("skolemid")) { - skid = children[1]->string(); - children += 2; - continue; - } - - ptr_vector proto_exprs; - - if (children[1]->kind() == proto_expr::COMMENT) { - std::string s = children[1]->string().str(); - std::istringstream stream(s); - scanner scanner(stream, get_err(), false); - proto_expr_parser parser(region, scanner, get_err()); - - if (!parser.parse(proto_exprs)) { - set_error("could not parse expression", children[1]); - return false; - } - } else if (children[1]->kind() == proto_expr::CONS) { - for (proto_expr* const* pexpr = children[1]->children(); *pexpr; pexpr++) - proto_exprs.push_back(*pexpr); - } else { - proto_exprs.push_back(children[1]); - } - - expr_ref_buffer ts(m_manager); - for (unsigned i = 0; i < proto_exprs.size(); ++i) { - expr_ref t(m_manager); - if (!make_expression(local_scope, proto_exprs[i], t)) { - return false; - } - ts.push_back(t.get()); - } - - if (children[0]->string() == symbol("pat") || - children[0]->string() == symbol("pats") || - children[0]->string() == symbol("pattern")) { - for (unsigned i = 0; i < ts.size(); ++i) { - if (!is_app(ts[i])) { - set_error("invalid pattern", children[0]); - return false; - } - } - expr_ref p(m_manager); - p = m_manager.mk_pattern(ts.size(), (app*const*)(ts.c_ptr())); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { - set_error("invalid pattern", children[0]); - return false; - } - patterns.push_back(p); - } - else if (children[0]->string() == symbol("ex_act") && ts.size() == 1) { - app_ref sk_hack(m_manager); - sk_hack = m_manager.mk_app(m_sk_hack, 1, ts.c_ptr()); - app * sk_hackp = sk_hack.get(); - expr_ref p(m_manager); - p = m_manager.mk_pattern(1, &sk_hackp); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { - set_error("invalid pattern", children[0]); - return false; - } - patterns.push_back(p); - } - else if ((children[0]->string() == symbol("nopat") || - children[0]->string() == symbol("no-pattern")) - && ts.size() == 1) { - no_patterns.push_back(ts[0]); - } - else if (children[0]->string() == symbol("weight") && ts.size() == 1 && - proto_exprs[0]->kind() == proto_expr::INT && - proto_exprs[0]->number().is_unsigned()) { - weight = proto_exprs[0]->number().get_unsigned(); - } - else { - // TODO: this should be a warning, perferably once per unknown kind of annotation - set_error("could not understand annotation '", - children[0]->string().bare_str(), "'", children[0]); - } - - children += 2; - } - return true; - } - - void set_default_num_sort(symbol const& name) { - if (name == symbol("QF_RDL") || - name == symbol("QF_LRA") || - name == symbol("LRA") || - name == symbol("RDL") || - name == symbol("QF_NRA") || - name == symbol("QF_UFNRA") || - name == symbol("QF_UFLRA")) { - m_int_sort = m_real_sort; - } - } - - bool get_sort(theory* th, char const * s, sort_ref& sort) { - return make_sort(symbol(s), 0, 0, sort); - } - - - bool make_sort(symbol const & id, unsigned num_params, parameter const* params, sort_ref& s) { - builtin_op info; - if (m_builtin_sorts.find(id, info)) { - s = m_manager.mk_sort(info.m_family_id, info.m_kind, num_params, params); - return true; - } - - if (num_params == 2 && symbol("Array") == id) { - // Old HACK to accomodate bit-vector arrays. - - if (!params[0].is_int()) { - throw default_exception("Non-integer parameter to array"); - return false; - } - if (!params[1].is_int()) { - throw default_exception("Non-integer parameter to array"); - return false; - } - parameter bv_params0[1] = { parameter(params[0].get_int()) }; - parameter bv_params1[1] = { parameter(params[1].get_int()) }; - - sort * t1 = m_manager.mk_sort(m_bv_fid, BV_SORT, 1, bv_params0); - sort * t2 = m_manager.mk_sort(m_bv_fid, BV_SORT, 1, bv_params1); - parameter params[2] = { parameter(t1), parameter(t2) }; - s = m_manager.mk_sort(m_array_fid, ARRAY_SORT, 2, params); - return true; - } - - sort* srt = 0; - if (m_benchmark.get_sort(id, srt)) { - s = srt; - return true; - } - return false; - } - - bool make_sort(proto_expr * e, sort_ref& s) { - SASSERT(can_be_sort(e)); - symtable& env = *m_benchmark.get_symtable(); - sort_builder* mk_sort; - switch(e->kind()) { - case proto_expr::ID: { - if (make_sort(e->string(), e->num_params(), e->params(), s)) { - return true; - } - if (env.lookup(e->string(), mk_sort)) { - if (!mk_sort->apply(e->num_params(), e->params(), s)) { - set_error(mk_sort->error_message(), e); - return false; - } - return true; - } - set_error("could not find sort ", e); - return false; - } - case proto_expr::CONS: { - if (!can_be_sort(e)) { - set_error("expression cannot be a sort", e); - return false; - } - proto_expr *const* chs = e->children(); - if (is_underscore(e)) { - ++chs; - } - symbol name = (*chs)->string(); - if (!env.lookup(name, mk_sort)) { - set_error("could not find sort symbol '", name.str(), "'", e); - return false; - } - sort_ref_vector sorts(m_manager); - vector params; - if (!parse_params(chs+1, params, sorts)) { - return false; - } - - if (!mk_sort->apply(params.size(), params.c_ptr(), s)) { - set_error(mk_sort->error_message(), e); - return false; - } - return true; - } - default: - set_error("could not create sort ", e); - return false; - } - } - - bool parse_params(proto_expr* const* chs,vector& params, sort_ref_vector& sorts) { - while (*chs) { - if ((*chs)->kind() == proto_expr::INT) { - rational const& num = (*chs)->number(); - if (num.is_unsigned()) { - params.push_back(parameter(num.get_unsigned())); - } - else { - params.push_back(parameter(num)); - } - } - else { - sort_ref s1(m_manager); - if (!make_sort(*chs, s1)) { - return false; - } - sorts.push_back(s1); - params.push_back(parameter((ast*)s1.get())); - } - ++chs; - } - return true; - } - - bool parse_bound( - symbol_table& local_scope, - region& region, - proto_expr* bound, - svector& vars, - sort_ref_buffer& sorts - ) - { - if (is_cons_list(bound)) { - proto_expr *const* children = bound->children(); - while (*children) { - if (!parse_bound(local_scope, region, *children, vars, sorts)) { - return false; - } - ++children; - } - return true; - } - if (!can_be_sorted_var(bound)) { - set_error("bound variable should contain a list of pairs", bound); - return false; - } - proto_expr* var = bound->children()[0]; - proto_expr* sort_proto_expr = bound->children()[1]; - - sort_ref sort(m_manager); - if (!make_sort(sort_proto_expr, sort)) { - return false; - } - sorts.push_back(sort); - vars.push_back(var->string()); - - local_scope.insert( - var->string(), - new (region) bound_var(this, sort) - ); - - ++m_binding_level; - - return true; - } - - bool can_be_sort(proto_expr* e) { - if (e && e->kind() == proto_expr::ID) { - return true; - } - if (is_underscore(e)) { - return true; - } - - if (e && - e->kind() == proto_expr::CONS && - e->children() && - e->children()[0] && - e->children()[1]) { - proto_expr* const* ch = e->children(); - while(*ch) { - if (!can_be_sort(*ch)) { - return false; - } - ++ch; - } - return true; - } - return false; - } - - bool declare_sorts(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - proto_expr* ch = *children; - switch(ch->kind()) { - - case proto_expr::ID: - m_benchmark.declare_sort(ch->string()); - break; - - case proto_expr::CONS: - // - // The declaration of type constructors - // consists of an identifier together with - // a number indicating the arity of the - // constructor. - // - if (ch->children() && - ch->children()[0] && - ch->children()[0]->kind() == proto_expr::ID && - ch->children()[1] && - ch->children()[1]->kind() == proto_expr::INT) { - - // unsigned num = (unsigned) ch->children()[1]->number().get_uint64(); - m_benchmark.declare_sort(ch->children()[0]->string()); - } - break; - - case proto_expr::ANNOTATION: - break; - - default: - set_error("unexpected argument to sorts",ch); - return false; - } - ++children; - } - return true; - } - - bool define_sorts(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - if (!define_sort(*children)) { - return false; - } - ++children; - } - return true; - } - - bool define_sort(proto_expr* e) { - proto_expr* const * children = e->children(); - sort_ref_buffer domain(m_manager); - - // - // First element in list must be an identifier. - // there should be just two elements. - // - if (!children || - !children[0] || - !(children[0]->kind() == proto_expr::ID) || - !children[1] || - children[2]) { - set_error("unexpected arguments to function declaration", e); - return false; - } - symbol name = children[0]->string(); - sort_ref s(m_manager); - if (!can_be_sort(children[1]) || - !make_sort(children[1], s)) { - set_error("unexpected arguments to function declaration", e); - return false; - } - - m_benchmark.get_symtable()->insert(name, s); - - return true; - } - - bool declare_funs(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - if (!declare_fun(*children)) { - return false; - } - ++children; - } - return true; - } - class define_sort_cls : public sort_builder { - smtparser& m_parser; - proto_region m_region; - proto_expr* m_expr; - svector m_params; - symbol m_name; - std::string m_error_message; - - public: - define_sort_cls(smtparser& p, symbol const& name, proto_expr* e, unsigned num_params, symbol* params) : - m_parser(p), - m_name(name) { - for (unsigned i = 0; i < num_params; ++i) { - m_params.push_back(params[i]); - } - m_expr = proto_expr::copy(m_region, e); - } - - virtual bool apply(unsigned num_params, parameter const* params, sort_ref & result) { - smtlib::symtable * symtable = m_parser.m_benchmark.get_symtable(); - if (m_params.size() != num_params) { - std::ostringstream strm; - strm << "wrong number of arguments passed to " << m_name << " " - << m_params.size() << " expected, but " << num_params << " given"; - m_error_message = strm.str(); - return false; - } - for (unsigned i = 0; i < num_params; ++i) { - parameter p(params[i]); - if (!p.is_ast() || !is_sort(p.get_ast())) { - symtable->pop_sorts(i); - std::ostringstream strm; - strm << "argument " << i << " is not a sort"; - m_error_message = strm.str(); - return false; - } - symtable->push_sort(m_params[i], to_sort(p.get_ast())); - } - bool success = m_parser.make_sort(m_expr, result); - - symtable->pop_sorts(num_params); - return success; - } - - virtual char const* error_message() { - return m_error_message.c_str(); - } - - }; - - // (define-sort name (*) ) - bool define_sort(proto_expr* id, proto_expr* sorts, proto_expr* srt) { - symbol name = id->string(); - proto_expr* const * children = sorts->children(); - svector names; - - if (!children) { - set_error("Sort definition expects a list of sort symbols",id); - return false; - } - - while (children[0]) { - id = children[0]; - if(id->kind() != proto_expr::ID) { - set_error("unexpected argument, expected ID", id); - return false; - } - names.push_back(id->string()); - ++children; - } - - m_benchmark.get_symtable()->insert(name, alloc(define_sort_cls, *this, name, srt, names.size(), names.c_ptr())); - return true; - } - - bool declare_fun(proto_expr* id, proto_expr* sorts, proto_expr* srt) { - proto_expr* const * children = sorts?sorts->children():0; - sort_ref_buffer domain(m_manager); - symbol name = id->string(); - - if (sorts && !children) { - set_error("Function declaration expects a list of sorts", id); - return false; - } - // - // parse domain. - // - while (sorts && children[0]) { - sort_ref s(m_manager); - if (!make_sort(children[0], s)) { - return false; - } - domain.push_back(s); - ++children; - } - - sort_ref range(m_manager); - if (!make_sort(srt, range)) { - return false; - } - bool is_associative = false; - bool is_commutative = false; - bool is_injective = false; - m_benchmark.declare_func(name, domain, range, is_associative, is_commutative, is_injective); - return true; - } - - bool declare_fun(proto_expr* e) { - proto_expr* const * children = e->children(); - sort_ref_buffer domain(m_manager); - // - // Skip declaration of numbers. - // - if (children && - children[0] && - children[0]->kind() == proto_expr::INT) { - return true; - } - - // - // First element in list must be an identifier. - // - if (!children || - !children[0] || - !(children[0]->kind() == proto_expr::ID)) { - set_error("unexpected arguments to function declaration", e); - return false; - } - - symbol name = children[0]->string(); - - ++children; - - - if (!can_be_sort(children[0])) { - set_error("unexpected arguments to function declaration", e); - return false; - } - - // - // parse domain. - // - while (can_be_sort(children[1])) { - sort_ref s(m_manager); - if (!make_sort(children[0], s)) { - return false; - } - domain.push_back(s); - ++children; - } - - // - // parse range. - // - SASSERT(can_be_sort(children[0])); - - sort_ref range(m_manager); - if (!make_sort(children[0], range)) { - return false; - } - ++children; - - // - // parse attributes. - // - bool is_associative = false; - bool is_commutative = false; - bool is_injective = false; - - while(children[0] && children[0]->kind() == proto_expr::ANNOTATION) { - - if (m_associative == children[0]->string()) { - is_associative = true; - } - else if (m_commutative == children[0]->string()) { - is_commutative = true; - } - else if (m_injective == children[0]->string()) { - is_injective = true; - } - ++children; - } - - m_benchmark.declare_func(name, domain, range, is_associative, is_commutative, is_injective); - - return true; - } - - bool declare_preds(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - if (!declare_pred(*children)) { - return false; - } - ++children; - } - return true; - } - - - bool declare_pred(proto_expr* e) { - proto_expr* const * children = e->children(); - if (!children || !children[0] || !(children[0]->kind() == proto_expr::ID)) { - set_error("unexpected arguments to predicate declaration", e); - return false; - } - symbol const & name = children[0]->string(); - sort_ref_buffer domain(m_manager); - sort * bool_sort = m_manager.mk_bool_sort(); - - ++children; - - while (can_be_sort(children[0])) { - sort_ref s(m_manager); - if (!make_sort(children[0], s)) { - return false; - } - domain.push_back(s); - ++children; - } - - m_benchmark.declare_func(name, domain, bool_sort, false, false, false); - - return true; - } - - bool can_be_sorted_var(proto_expr* e) { - return - e && - (e->kind() == proto_expr::CONS) && - e->children() && - e->children()[0] && - (e->children()[0]->kind() == proto_expr::ID) && - can_be_sort(e->children()[1]); - } - - bool is_cons_list(proto_expr* e) { - return - e && - (e->kind() == proto_expr::CONS) && - e->children() && - e->children()[0] && - e->children()[0]->kind() == proto_expr::CONS; - } - - bool is_prefixed(proto_expr* e, symbol const& s) { - return - e && - (e->kind() == proto_expr::CONS) && - e->children() && - e->children()[0] && - e->children()[1] && - e->children()[0]->string() == s; - - } - - bool is_underscore(proto_expr* e) { - return - is_prefixed(e, m_underscore) && - e->children()[1]->kind() == proto_expr::ID; - } - - bool is_annotated_cons(proto_expr* e) { - return is_prefixed(e, m_bang); - } - - bool is_builtin_const(symbol const& id, proto_expr* current, unsigned num_params, parameter * params, bool& ok, expr_ref& term) { - builtin_op info; - ok = true; - if (!m_builtin_ops.find(id, info)) { - return false; - } - fix_parameters(num_params, params); - func_decl* d = m_manager.mk_func_decl(info.m_family_id, info.m_kind, num_params, params, 0, (expr * const *)0); - if (!d) { - set_error("could not create a term from constant ", id, current); - ok = false; - } - else if (d->get_arity() != 0) { - set_error("identifier expects arguments ", id, current); - ok = false; - } - else { - term = m_manager.mk_const(d); - } - return true; - } - - bool is_underscore_op(region& r, proto_expr* e, idbuilder*& builder) { - if (!is_underscore(e)) { - return false; - } - builtin_op info; - proto_expr *const* chs = e->children()+1; - symbol const& id = (*chs)->string(); - sort_ref_vector sorts(m_manager); - vector params; - - if (!m_builtin_ops.find(id, info)) { - return false; - } - if (!parse_params(chs+1, params, sorts)) { - return false; - } - - builder = new (r) builtin_builder(this, info.m_family_id, info.m_kind, params); - return true; - } - - void fix_parameters(unsigned num_params, parameter* params) { - for (unsigned i = 0; i < num_params; ++i) { - func_decl* d = 0; - sort* s = 0; - builtin_op info; - if (params[i].is_symbol() && m_benchmark.get_symtable()->find1(params[i].get_symbol(), d)) { - params[i] = parameter(d); - } - else if (params[i].is_symbol() && m_benchmark.get_symtable()->find(params[i].get_symbol(), s)) { - params[i] = parameter(s); - } - else if (params[i].is_symbol() && m_builtin_sorts.find(params[i].get_symbol(), info)) { - params[i] = parameter(m_manager.mk_sort(info.m_family_id, info.m_kind, 0, 0)); - } - } - } - - bool make_app(proto_expr * proto_expr, expr_ref_vector const & args, expr_ref & result) { - symbol const& name = proto_expr->string(); - ptr_vector sorts; - func_decl * d = 0; - smtlib::symtable * symtable = m_benchmark.get_symtable(); - - for (unsigned i = 0; i < args.size(); ++i) { - sorts.push_back(m_manager.get_sort(args.get(i))); - } - - if (symtable->find_overload(name, sorts, d)) { - result = m_manager.mk_app(d, args.size(), args.c_ptr()); - return true; - } - - builtin_op info; - if (m_builtin_ops.find(name, info)) { - unsigned num_params = proto_expr->num_params(); - parameter * params = proto_expr->params(); - fix_parameters(num_params, params); - d = m_manager.mk_func_decl(info.m_family_id, info.m_kind, num_params, params, args.size(), args.c_ptr()); - if (d) { - result = m_manager.mk_app(d, args.size(), args.c_ptr()); - return true; - } - } - - rational arg2_value; - bool arg2_is_int; - - if (name == symbol("store") && - args.size() == 3 && - m_anum_util.is_numeral(args.get(2), arg2_value, arg2_is_int) && - arg2_is_int) { - expr_ref_vector new_args(m_manager); - new_args.push_back(args.get(0)); - new_args.push_back(args.get(1)); - new_args.push_back(m_anum_util.mk_numeral(arg2_value, false)); - sorts.reset(); - for (unsigned i = 0; i < args.size(); ++i) { - sorts.push_back(m_manager.get_sort(new_args.get(i))); - } - if (symtable->find_overload(name, sorts, d)) { - result = m_manager.mk_app(d, new_args.size(), new_args.c_ptr()); - return true; - } - } - - error_prefix(proto_expr); - get_err() << "could not find overload for '" << name << "' "; - for (unsigned i = 0; i < sorts.size(); ++i) { - get_err() << "Argument: " - << mk_pp(args.get(i), m_manager) - << " has type " - << mk_pp(sorts[i], m_manager) - << ".\n"; - } - return false; - } - - class nullary : public idbuilder { - expr* m_expr; - smtparser* m_parser; - unsigned m_decl_level_save; - public: - nullary(expr* e, smtparser* p) : m_expr(e), m_parser(p), m_decl_level_save(p->m_binding_level) {} - - virtual bool apply(expr_ref_vector const& args, expr_ref & result) { - unsigned decl_level = m_parser->m_binding_level; - SASSERT(decl_level >= m_decl_level_save); - shift_vars shifty(m_parser->m_manager); - shifty(m_expr, decl_level - m_decl_level_save, result); - return (args.size() == 0); - } - }; - - class identity : public idbuilder { - public: - identity() {} - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() == 1) { - result = args.back(); - return true; - } - else { - return false; - } - } - }; - - class parse_frame { - public: - - parse_frame(proto_expr * e, idbuilder * make, expr_ref_vector * left, proto_expr * const* right, unsigned binding_level): - m_proto_expr(e), - m_make_term(make), - m_left(left), - m_right(right), - m_binding_level(binding_level) { - } - - parse_frame(proto_expr * e, expr_ref_vector * left, proto_expr * const* right, unsigned binding_level): - m_proto_expr(e), - m_make_term(0), - m_left(left), - m_right(right), - m_binding_level(binding_level) { - } - - expr_ref_vector * detach_left() { - expr_ref_vector * result = m_left; - SASSERT(m_left); - m_left = 0; - return result; - } - - unsigned binding_level() const { return m_binding_level; } - - proto_expr* const * right() const { return m_right; } - - idbuilder* make_term() { return m_make_term; } - - proto_expr* get_proto_expr() const { return m_proto_expr; } - - ~parse_frame() { dealloc(m_left); } - - private: - - proto_expr* m_proto_expr; - idbuilder* m_make_term; - expr_ref_vector * m_left; - proto_expr* const * m_right; - unsigned m_binding_level; - - parse_frame & operator=(parse_frame const & other); - - parse_frame(parse_frame const & other); - - }; - - class build_label : public idbuilder { - bool m_pos; - symbol m_sym; - smtparser * m_smt; - public: - build_label(smtparser * smt, bool is_pos, proto_expr * sym): m_pos(is_pos), m_smt(smt) { - switch(sym->kind()) { - case proto_expr::ID: - case proto_expr::STRING: - m_sym = sym->string(); - break; - case proto_expr::INT: - m_sym = symbol(sym->number().to_string().c_str()); - break; - default: - UNREACHABLE(); - break; - } - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() >= 1) { - result = m_smt->m_manager.mk_label(m_pos, m_sym, args.get(0)); - return true; - } - else { - return false; - } - } - }; - - class pop_let : public idbuilder { - public: - pop_let(symbol_table & local_scope, expr_ref_vector* pinned = 0): - m_local_scope(local_scope), - m_pinned(pinned) { - } - - virtual ~pop_let() {} - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - dealloc(m_pinned); - if (args.size() == 2) { - m_local_scope.end_scope(); - result = args.get(1); - return true; - } - else { - return false; - } - } - private: - symbol_table & m_local_scope; - expr_ref_vector* m_pinned; - }; - - class push_let : public idbuilder { - smtparser* m_parser; - region & m_region; - symbol_table & m_local_scope; - symbol m_let_var; - - public: - push_let(smtparser* p, region & region, symbol_table & local_scope, symbol const & let_var): - m_parser(p), - m_region(region), - m_local_scope(local_scope), - m_let_var(let_var) { - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - // - // . push a scope, - // . create a nullary function using the variable/term association. - // . return the (first) argument. - // - // - if (args.size() == 1) { - m_local_scope.begin_scope(); - m_local_scope.insert(m_let_var, new (m_region) nullary(args.back(), m_parser)); - result = args.back(); - return true; - } - else { - return false; - } - } - }; - - // push multiple let bound variables. - class push_let_and : public idbuilder { - smtparser* m_parser; - region & m_region; - symbol_table & m_local_scope; - unsigned m_num_vars; - symbol* m_vars; - expr_ref_vector* m_pinned; - - public: - push_let_and(smtparser* p, region & region, symbol_table & local_scope, expr_ref_vector* pinned, unsigned num_vars, symbol const* vars): - m_parser(p), - m_region(region), - m_local_scope(local_scope), - m_num_vars(num_vars), - m_vars(new (region) symbol[num_vars]), - m_pinned(pinned) { - for (unsigned i = 0; i < num_vars; ++i) { - m_vars[i] = vars[i]; - } - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() != m_num_vars) { - return false; - } - - // - // . push a scope, - // . create a nullary function using the variable/term association. - // . return the last argument (arbitrary). - // - - m_local_scope.begin_scope(); - for (unsigned i = 0; i < m_num_vars; ++i) { - m_local_scope.insert(m_vars[i], new (m_region) nullary(args[i], m_parser)); - m_pinned->push_back(args[i]); - } - result = args.back(); - return true; - } - }; - - class bound_var : public idbuilder { - public: - bound_var(smtparser * smt, sort * sort): - m_smt(smt), - m_decl_level(smt->m_binding_level), - m_sort(sort) { - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - SASSERT(m_smt->m_binding_level > m_decl_level); - unsigned idx = m_smt->m_binding_level - m_decl_level - 1; - result = m_smt->m_manager.mk_var(idx, m_sort); - return args.empty(); - } - - private: - smtparser * m_smt; - unsigned m_decl_level; - sort * m_sort; - }; - - class pop_quantifier : public idbuilder { - public: - pop_quantifier(smtparser * smt, bool is_forall, int weight, symbol const& qid, symbol const& skid, expr_ref_buffer & patterns, expr_ref_buffer & no_patterns, sort_ref_buffer & sorts, - svector& vars, symbol_table & local_scope): - m_smt(smt), - m_is_forall(is_forall), - m_weight(weight), - m_qid(qid), - m_skid(skid), - m_patterns(m_smt->m_manager), - m_no_patterns(m_smt->m_manager), - m_sorts(m_smt->m_manager), - m_local_scope(local_scope) { - SASSERT(sorts.size() == vars.size()); - - m_vars.append(vars); - m_sorts.append(sorts); - m_patterns.append(patterns); - m_no_patterns.append(no_patterns); - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() != 1) { - return false; - } - - m_local_scope.end_scope(); - - expr * body = args.back(); - - if (m_smt->ignore_user_patterns()) { - TRACE("pat_bug", tout << "ignoring user patterns...: " << m_patterns.size() << "\n";); - result = m_smt->m_manager.mk_quantifier(m_is_forall, - m_sorts.size(), // num_decls - m_sorts.c_ptr(), // decl_sorts - m_vars.begin(), // decl_names - body, - m_weight, - m_qid, - m_skid, - 0, - 0, - 0, - 0); - } - else if (!m_patterns.empty()) { - if (!m_no_patterns.empty()) { - m_smt->set_error("patterns were provided, ignoring :nopat attribute.", ((proto_expr*)0)); - } - result = m_smt->m_manager.mk_quantifier(m_is_forall, - m_sorts.size(), // num_decls - m_sorts.c_ptr(), // decl_sorts - m_vars.begin(), // decl_names - body, - m_weight, - m_qid, - m_skid, - m_patterns.size(), - m_patterns.c_ptr(), - 0, - 0); - } - else { - result = m_smt->m_manager.mk_quantifier(m_is_forall, - m_sorts.size(), // num_decls - m_sorts.c_ptr(), // decl_sorts - m_vars.begin(), // decl_names - body, - m_weight, - m_qid, - m_skid, - 0, - 0, - m_no_patterns.size(), - m_no_patterns.c_ptr()); - } - - // - // reclaim memory resources on application. - // - - m_vars.finalize(); - m_sorts.finalize(); - m_patterns.finalize(); - m_no_patterns.finalize(); - return true; - } - - private: - smtparser* m_smt; - bool m_is_forall; - int m_weight; - symbol m_qid; - symbol m_skid; - expr_ref_buffer m_patterns; - expr_ref_buffer m_no_patterns; - sort_ref_buffer m_sorts; - svector m_vars; - symbol_table& m_local_scope; - }; - - class builtin_builder : public idbuilder { - smtparser* m_smt; - family_id m_fid; - decl_kind m_kind; - vector m_params; - - public: - builtin_builder(smtparser* smt, family_id fid, decl_kind k,vector const& p): - m_smt(smt), - m_fid(fid), - m_kind(k), - m_params(p) - { - } - - virtual bool apply(expr_ref_vector const& args, expr_ref& result) { - ast_manager& m = m_smt->m_manager; - func_decl* d = m.mk_func_decl(m_fid, m_kind, m_params.size(), m_params.c_ptr(), args.size(), args.c_ptr()); - if (d) { - result = m.mk_app(d, args.size(), args.c_ptr()); - } - m_params.finalize(); - return d != 0; - } - }; - - bool push_status(smtlib::benchmark::status status) { - m_benchmark.set_status( status); - return true; - } - - expr * mk_number(rational const & r, bool is_int){ - if (m_int_sort == m_real_sort) // integer constants should be mapped to real - is_int = false; - return m_anum_util.mk_numeral(r, is_int); - } - - void push_benchmark(symbol const & name) { - m_benchmark.set_name(name); - } - - bool push_assumption(expr * t) { - m_benchmark.add_axiom(t); - return true; - } - - bool push_formula(expr * t) { - m_benchmark.add_formula(t); - return true; - } - - bool is_binary_let_binding(proto_expr* let_binding) { - return - let_binding && - let_binding->children() && - let_binding->children()[0] && - (let_binding->children()[0]->kind() == proto_expr::ID) && - let_binding->children()[1] && - !let_binding->children()[2]; - } - - bool is_bvconst(symbol const & fname, unsigned num_params, parameter const* params, expr_ref & term) { - rational n; - char const * str = fname.bare_str(); - unsigned sz = 0; - - if (strncmp(str, "bvbin", 5) == 0) { - str += 5; - n = rational(0); - while (*str == '1' || *str == '0') { - n *= rational(2); - n += rational(*str - '0'); - ++sz; - ++str; - } - if (sz == 0) { - return false; - } - } - else if (strncmp(str, "bvhex", 5) == 0) { - n = rational(0); - str += 5; - while (('0' <= *str && *str <= '9') || - ('a' <= *str && *str <= 'f') || - ('A' <= *str && *str <= 'F')) { - n *= rational(16); - if ('0' <= *str && *str <= '9') { - n += rational(*str - '0'); - } - else if ('a' <= *str && *str <= 'f') { - n += rational(10); - n += rational(*str - 'a'); - } - else { - SASSERT('A' <= *str && *str <= 'F'); - n += rational(10); - n += rational(*str - 'A'); - } - sz += 4; - ++str; - } - if (sz == 0) { - return false; - } - } - else if (strncmp(str, "bv", 2) == 0 && '0' <= *(str + 2) && *(str + 2) <= '9') { - n = rational(0); - str += 2; - while ('0' <= *str && *str <= '9') { - n *= rational(10); - n += rational(*str - '0'); - ++str; - } - if (num_params == 1) { - sz = params[0].get_int(); - } - else { - sz = 32; - } - } - else { - return false; - } - - term = m_bvnum_util.mk_numeral(n, sz); - - return true; - } -}; - - -parser * parser::create(ast_manager& ast_manager, bool ignore_user_patterns) { - return alloc(smtparser, ast_manager, ignore_user_patterns); -} diff --git a/src/parsers/smt/smtparser.h b/src/parsers/smt/smtparser.h deleted file mode 100644 index d8999e8ab..000000000 --- a/src/parsers/smt/smtparser.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtparser.h - -Abstract: - - SMT parsing utilities - -Author: - - Nikolaj Bjorner (nbjorner) 2006-09-25 - -Revision History: - ---*/ -#ifndef SMT_PARSER_H_ -#define SMT_PARSER_H_ - -#include -#include "ast/ast.h" -#include "util/vector.h" -#include "parsers/smt/smtlib.h" - -namespace smtlib { - class parser { - public: - static parser * create(ast_manager & ast_manager, bool ignore_user_patterns = false); - - virtual ~parser() {} - - virtual void add_builtin_op(char const *, family_id fid, decl_kind kind) = 0; - virtual void add_builtin_type(char const *, family_id fid, decl_kind kind) = 0; - - virtual void initialize_smtlib() = 0; - - virtual void set_error_stream(std::ostream& strm) = 0; - - virtual bool parse_file(char const * path) = 0; - virtual bool parse_string(char const * string) = 0; - - virtual benchmark * get_benchmark() = 0; - }; -}; - -#endif diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index fd592f7c7..a06438c73 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -867,7 +867,7 @@ namespace smt2 { throw parser_exception("invalid datatype declaration, too many data-type bodies defined"); } symbol dt_name = m_dt_names[i]; - parse_datatype_dec(new_ct_decls); + parse_datatype_dec(nullptr, new_ct_decls); d = pm().mk_pdatatype_decl(m_dt_name2arity.find(dt_name), dt_name, new_ct_decls.size(), new_ct_decls.c_ptr()); } else { @@ -942,7 +942,7 @@ namespace smt2 { pdatatype_decl_ref d(pm()); pconstructor_decl_ref_buffer new_ct_decls(pm()); - parse_datatype_dec(new_ct_decls); + parse_datatype_dec(&dt_name, new_ct_decls); d = pm().mk_pdatatype_decl(m_sort_id2param_idx.size(), dt_name, new_ct_decls.size(), new_ct_decls.c_ptr()); check_missing(d, line, pos); @@ -956,12 +956,16 @@ namespace smt2 { // datatype_dec ::= ( constructor_dec+ ) | ( par ( symbol+ ) ( constructor_dec+ ) ) - void parse_datatype_dec(pconstructor_decl_ref_buffer & ct_decls) { + void parse_datatype_dec(symbol* dt_name, pconstructor_decl_ref_buffer & ct_decls) { check_lparen_next("invalid datatype declaration, '(' expected"); if (curr_id() == m_par) { next(); parse_sort_decl_params(); check_lparen_next("invalid constructor declaration after par, '(' expected"); + unsigned sz = m_sort_id2param_idx.size(); + if (sz > 0 && dt_name) { + m_ctx.insert(pm().mk_psort_dt_decl(sz, *dt_name)); + } parse_constructor_decls(ct_decls); check_rparen_next("invalid datatype declaration, ')' expected"); } diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 1f9c89f89..e28f6ae4f 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -782,7 +782,7 @@ namespace qe { m(m), m_mode(mode), m_params(p), - m_solver(m.limit(), p), + m_solver(m.limit(), p, true), m_nftactic(0), m_rmodel(m_solver.am()), m_rmodel0(m_solver.am()), @@ -886,174 +886,6 @@ namespace qe { tactic * translate(ast_manager & m) { return alloc(nlqsat, m, m_mode, m_params); } - -#if 0 - - /** - - Algorithm: - I := true - while there is M, such that M |= ~B & I: - find P, such that M => P => exists y . ~B & I - ; forall y B => ~P - C := core of P with respect to A - ; A => ~ C => ~ P - I := I & ~C - - - Alternative Algorithm: - R := false - while there is M, such that M |= A & ~R: - find I, such that M => I => forall y . B - R := R | I - - */ - - lbool interpolate(expr* a, expr* b, expr_ref& result) { - SASSERT(m_mode == interp_t); - - reset(); - app_ref enableA(m), enableB(m); - expr_ref A(m), B(m), fml(m); - expr_ref_vector fmls(m), answer(m); - - // varsB are private to B. - nlsat::var_vector vars; - uint_set fvars; - private_vars(a, b, vars, fvars); - - enableA = m.mk_const(symbol("#A"), m.mk_bool_sort()); - enableB = m.mk_not(enableA); - A = m.mk_implies(enableA, a); - B = m.mk_implies(enableB, m.mk_not(b)); - fml = m.mk_and(A, B); - hoist(fml); - - - - nlsat::literal _enableB = nlsat::literal(m_a2b.to_var(enableB), false); - nlsat::literal _enableA = ~_enableB; - - while (true) { - m_mode = qsat_t; - // enable B - m_assumptions.reset(); - m_assumptions.push_back(_enableB); - lbool is_sat = check_sat(); - - switch (is_sat) { - case l_undef: - return l_undef; - case l_true: - break; - case l_false: - result = mk_and(answer); - return l_true; - } - - // disable B, enable A - m_assumptions.reset(); - m_assumptions.push_back(_enableA); - // add blocking clause to solver. - - nlsat::scoped_literal_vector core(m_solver); - - m_mode = elim_t; - - mbp(vars, fvars, core); - - // minimize core. - nlsat::literal_vector _core(core.size(), core.c_ptr()); - _core.push_back(_enableA); - is_sat = m_solver.check(_core); // TBD: only for quantifier-free A. Generalize output of elim_t to be a core. - switch (is_sat) { - case l_undef: - return l_undef; - case l_true: - UNREACHABLE(); - case l_false: - core.reset(); - core.append(_core.size(), _core.c_ptr()); - break; - } - negate_clause(core); - // keep polarity of enableA, such that clause is only - // used when checking satisfiability of B. - for (unsigned i = 0; i < core.size(); ++i) { - if (core[i].var() == _enableA.var()) core.set(i, ~core[i]); - } - add_clause(core); // Invariant is added as assumption for B. - answer.push_back(clause2fml(core)); // TBD: remove answer literal. - } - } - - /** - \brief extract variables that are private to a (not used in b). - vars cover the real variables, and fvars cover the Boolean variables. - - TBD: We want fvars to be the complement such that returned core contains - Shared boolean variables, but not the ones private to B. - */ - void private_vars(expr* a, expr* b, nlsat::var_vector& vars, uint_set& fvars) { - app_ref_vector varsA(m), varsB(m); - obj_hashtable varsAS; - pred_abs abs(m); - abs.get_free_vars(a, varsA); - abs.get_free_vars(b, varsB); - insert_set(varsAS, varsA); - for (unsigned i = 0; i < varsB.size(); ++i) { - if (varsAS.contains(varsB[i].get())) { - varsB[i] = varsB.back(); - varsB.pop_back(); - --i; - } - } - for (unsigned j = 0; j < varsB.size(); ++j) { - app* v = varsB[j].get(); - if (m_a2b.is_var(v)) { - fvars.insert(m_a2b.to_var(v)); - } - else if (m_t2x.is_var(v)) { - vars.push_back(m_t2x.to_var(v)); - } - } - } - - lbool maximize(app* _x, expr* _fml, scoped_anum& result, bool& unbounded) { - expr_ref fml(_fml, m); - reset(); - hoist(fml); - nlsat::literal_vector lits; - lbool is_sat = l_true; - nlsat::var x = m_t2x.to_var(_x); - m_mode = qsat_t; - while (is_sat == l_true) { - is_sat = check_sat(); - if (is_sat == l_true) { - // m_asms is minimized set of literals that satisfy formula. - nlsat::explain& ex = m_solver.get_explain(); - polynomial::manager& pm = m_solver.pm(); - anum_manager& am = m_solver.am(); - ex.maximize(x, m_asms.size(), m_asms.c_ptr(), result, unbounded); - if (unbounded) { - break; - } - // TBD: assert the new bound on x using the result. - bool is_even = false; - polynomial::polynomial_ref pr(pm); - pr = pm.mk_polynomial(x); - rational r; - am.get_upper(result, r); - // result is algebraic numeral, but polynomials are not defined over extension field. - polynomial::polynomial* p = pr; - nlsat::bool_var b = m_solver.mk_ineq_atom(nlsat::atom::GT, 1, &p, &is_even); - nlsat::literal bound(b, false); - m_solver.mk_clause(1, &bound); - } - } - return is_sat; - } -#endif }; }; diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 01806bc24..3975945cb 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -974,7 +974,7 @@ namespace ar { // ------------------------------------------------------------ -// fm_tactic adapted to eliminate designated de-Brujin indices. +// fm_tactic adapted to eliminate designated de-Bruijn indices. namespace fm { typedef ptr_vector clauses; diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 3d2609c4f..f0e640d66 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -35,9 +35,10 @@ Revision History: #include "util/error_codes.h" #include "util/gparams.h" #include "util/env_params.h" +#include "util/file_path.h" #include "shell/lp_frontend.h" -typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; +typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; std::string g_aux_input_file; char const * g_input_file = 0; @@ -169,9 +170,6 @@ void parse_cmd_line_args(int argc, char ** argv) { std::cout << "\n"; exit(0); } - else if (strcmp(opt_name, "smt") == 0) { - g_input_kind = IN_SMTLIB; - } else if (strcmp(opt_name, "smt2") == 0) { g_input_kind = IN_SMTLIB_2; } @@ -289,19 +287,6 @@ void parse_cmd_line_args(int argc, char ** argv) { } } -char const * get_extension(char const * file_name) { - if (file_name == 0) - return 0; - char const * last_dot = 0; - for (;;) { - char const * tmp = strchr(file_name, '.'); - if (tmp == 0) { - return last_dot; - } - last_dot = tmp + 1; - file_name = last_dot; - } -} int STD_CALL main(int argc, char ** argv) { try{ @@ -340,9 +325,6 @@ int STD_CALL main(int argc, char ** argv) { else if (strcmp(ext, "smt2") == 0) { g_input_kind = IN_SMTLIB_2; } - else if (strcmp(ext, "smt") == 0) { - g_input_kind = IN_SMTLIB; - } else if (strcmp(ext, "mps") == 0 || strcmp(ext, "sif") == 0 || strcmp(ext, "MPS") == 0 || strcmp(ext, "SIF") == 0) { g_input_kind = IN_MPS; @@ -350,9 +332,6 @@ int STD_CALL main(int argc, char ** argv) { } } switch (g_input_kind) { - case IN_SMTLIB: - return_value = read_smtlib_file(g_input_file); - break; case IN_SMTLIB_2: memory::exit_when_out_of_memory(true, "(error \"out of memory\")"); return_value = read_smtlib2_commands(g_input_file); diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index e1aff8669..8154cbde4 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/gparams.h" #include "util/timeout.h" #include "ast/reg_decl_plugins.h" +#include "opt/opt_parse.h" extern bool g_display_statistics; static bool g_first_interrupt = true; @@ -20,262 +21,6 @@ static opt::context* g_opt = 0; static double g_start_time = 0; static unsigned_vector g_handles; -class opt_stream_buffer { - std::istream & m_stream; - int m_val; - unsigned m_line; -public: - opt_stream_buffer(std::istream & s): - m_stream(s), - m_line(0) { - m_val = m_stream.get(); - } - int operator *() const { return m_val;} - void operator ++() { m_val = m_stream.get(); } - int ch() const { return m_val; } - void next() { m_val = m_stream.get(); } - bool eof() const { return ch() == EOF; } - unsigned line() const { return m_line; } - void skip_whitespace() { - while ((ch() >= 9 && ch() <= 13) || ch() == 32) { - if (ch() == 10) ++m_line; - next(); - } - } - void skip_space() { - while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { - next(); - } - } - void skip_line() { - while(true) { - if (eof()) { - return; - } - if (ch() == '\n') { - ++m_line; - next(); - return; - } - next(); - } - } - - bool parse_token(char const* token) { - skip_whitespace(); - char const* t = token; - while (ch() == *t) { - next(); - ++t; - } - return 0 == *t; - } - - int parse_int() { - int val = 0; - bool neg = false; - skip_whitespace(); - - if (ch() == '-') { - neg = true; - next(); - } - else if (ch() == '+') { - next(); - } - if (ch() < '0' || ch() > '9') { - std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; - exit(3); - } - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - return neg ? -val : val; - } - - unsigned parse_unsigned() { - skip_space(); - if (ch() == '\n') { - return UINT_MAX; - } - unsigned val = 0; - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - return val; - } -}; - -class wcnf { - opt::context& opt; - ast_manager& m; - opt_stream_buffer& in; - - app_ref read_clause(unsigned& weight) { - int parsed_lit; - int var; - weight = in.parse_unsigned(); - app_ref result(m), p(m); - expr_ref_vector ors(m); - while (true) { - parsed_lit = in.parse_int(); - if (parsed_lit == 0) - break; - var = abs(parsed_lit); - p = m.mk_const(symbol(var), m.mk_bool_sort()); - if (parsed_lit < 0) p = m.mk_not(p); - ors.push_back(p); - } - result = to_app(mk_or(m, ors.size(), ors.c_ptr())); - return result; - } - - void parse_spec(unsigned& num_vars, unsigned& num_clauses, unsigned& max_weight) { - in.parse_token("wcnf"); - num_vars = in.parse_unsigned(); - num_clauses = in.parse_unsigned(); - max_weight = in.parse_unsigned(); - } - -public: - - wcnf(opt::context& opt, opt_stream_buffer& in): opt(opt), m(opt.get_manager()), in(in) { - opt.set_clausal(true); - } - - void parse() { - unsigned num_vars = 0, num_clauses = 0, max_weight = 0; - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == 'c') { - in.skip_line(); - } - else if (*in == 'p') { - ++in; - parse_spec(num_vars, num_clauses, max_weight); - } - else { - unsigned weight = 0; - app_ref cls = read_clause(weight); - if (weight >= max_weight) { - opt.add_hard_constraint(cls); - } - else { - unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); - if (g_handles.empty()) { - g_handles.push_back(id); - } - } - } - } - } -}; - - -class opb { - opt::context& opt; - ast_manager& m; - opt_stream_buffer& in; - arith_util arith; - - app_ref parse_id() { - bool negated = in.parse_token("~"); - if (!in.parse_token("x")) { - std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\")\n"; - exit(3); - } - app_ref p(m); - int id = in.parse_int(); - p = m.mk_const(symbol(id), m.mk_bool_sort()); - if (negated) p = m.mk_not(p); - in.skip_whitespace(); - return p; - } - - app_ref parse_ids() { - app_ref result = parse_id(); - while (*in == '~' || *in == 'x') { - result = m.mk_and(result, parse_id()); - } - return result; - } - - rational parse_coeff_r() { - in.skip_whitespace(); - svector num; - bool pos = true; - if (*in == '-') pos = false, ++in; - if (*in == '+') ++in; - if (!pos) num.push_back('-'); - in.skip_whitespace(); - while ('0' <= *in && *in <='9') num.push_back(*in), ++in; - num.push_back(0); - return rational(num.c_ptr()); - } - - app_ref parse_coeff() { - return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); - } - - app_ref parse_term() { - app_ref c = parse_coeff(); - app_ref e = parse_ids(); - return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); - } - - void parse_objective() { - app_ref t = parse_term(); - while (!in.parse_token(";") && !in.eof()) { - t = arith.mk_add(t, parse_term()); - } - g_handles.push_back(opt.add_objective(t, false)); - } - - void parse_constraint() { - app_ref t = parse_term(); - while (!in.eof()) { - if (in.parse_token(">=")) { - t = arith.mk_ge(t, parse_coeff()); - in.parse_token(";"); - break; - } - if (in.parse_token("=")) { - t = m.mk_eq(t, parse_coeff()); - in.parse_token(";"); - break; - } - t = arith.mk_add(t, parse_term()); - } - opt.add_hard_constraint(t); - } -public: - opb(opt::context& opt, opt_stream_buffer& in): - opt(opt), m(opt.get_manager()), - in(in), arith(m) {} - - void parse() { - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == '*') { - in.skip_line(); - } - else if (in.parse_token("min:")) { - parse_objective(); - } - else { - parse_constraint(); - } - } - } -}; static void display_results() { @@ -335,14 +80,11 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { g_opt = &opt; params_ref p = gparams::get_module("opt"); opt.updt_params(p); - opt_stream_buffer _in(in); if (is_wcnf) { - wcnf wcnf(opt, _in); - wcnf.parse(); + parse_wcnf(opt, in, g_handles); } else { - opb opb(opt, _in); - opb.parse(); + parse_opb(opt, in, g_handles); } try { lbool r = opt.optimize(); diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 666a1e1fe..8c716a81a 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -21,7 +21,6 @@ Revision History: #include #include #include -#include "parsers/smt/smtlib_solver.h" #include "util/timeout.h" #include "parsers/smt2/smt2parser.h" #include "muz/fp/dl_cmds.h" @@ -35,20 +34,14 @@ Revision History: extern bool g_display_statistics; static clock_t g_start_time; -static smtlib::solver* g_solver = 0; static cmd_context * g_cmd_context = 0; static void display_statistics() { clock_t end_time = clock(); - if ((g_solver || g_cmd_context) && g_display_statistics) { + if (g_cmd_context && g_display_statistics) { std::cout.flush(); std::cerr.flush(); - if (g_solver) { - g_solver->display_statistics(); - memory::display_max_usage(std::cout); - std::cout << "time: " << ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC) << " secs\n"; - } - else if (g_cmd_context) { + if (g_cmd_context) { g_cmd_context->set_regular_stream("stdout"); g_cmd_context->display_statistics(true, ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC)); } @@ -72,33 +65,6 @@ static void STD_CALL on_ctrl_c(int) { raise(SIGINT); } -unsigned read_smtlib_file(char const * benchmark_file) { - g_start_time = clock(); - register_on_timeout_proc(on_timeout); - signal(SIGINT, on_ctrl_c); - smtlib::solver solver; - g_solver = &solver; - - bool ok = true; - - ok = solver.solve_smt(benchmark_file); - if (!ok) { - if (benchmark_file) { - std::cerr << "ERROR: solving '" << benchmark_file << "'.\n"; - } - else { - std::cerr << "ERROR: solving input stream.\n"; - } - } - - #pragma omp critical (g_display_stats) - { - display_statistics(); - register_on_timeout_proc(0); - g_solver = 0; - } - return solver.get_error_code(); -} unsigned read_smtlib2_commands(char const * file_name) { g_start_time = clock(); diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 56600266a..6ddce341d 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -131,6 +131,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { p.set_bool("gcd_rounding", true); p.set_bool("expand_select_store", true); p.set_bool("bv_sort_ac", true); + p.set_bool("som", true); m_rewriter.updt_params(p); flush_cache(); } diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 96334e3ce..c979e476e 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -188,7 +188,7 @@ namespace smt { 1) Variables: (f ... X ...) 2) Ground terms: (f ... t ...) 3) depth 2 joint: (f ... (g ... X ...) ...) - Joint2 stores the declartion g, and the position of variable X, and its idx. + Joint2 stores the declaration g, and the position of variable X, and its idx. \remark Z3 has no support for depth 3 joints (f ... (g ... (h ... X ...) ...) ....) */ @@ -211,7 +211,7 @@ namespace smt { approx_set m_lbl_set; // singleton set containing m_label /* The following field is an array of tagged pointers. - Each positon contains: + Each position contains: 1- null (no joint), NULL_TAG 2- a boxed integer (i.e., register that contains the variable bind) VAR_TAG 3- an enode pointer (ground term) GROUND_TERM_TAG diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 7f35feb64..122d09f32 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -74,7 +74,7 @@ def_module_params(module_name='smt', ('str.fast_length_tester_cache', BOOL, False, 'cache length tester constants instead of regenerating them'), ('str.fast_value_tester_cache', BOOL, True, 'cache value tester constants instead of regenerating them'), ('str.string_constant_cache', BOOL, True, 'cache all generated string constants generated from anywhere in theory_str'), - ('str.use_binary_search', BOOL, True, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'), + ('str.use_binary_search', BOOL, False, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'), ('str.binary_search_start', UINT, 64, 'initial upper bound for theory_str binary search'), ('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'), ('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'), diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3b69d4846..a87042e2b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3202,10 +3202,8 @@ namespace smt { }); validate_unsat_core(); // theory validation of unsat core - ptr_vector::iterator th_it = m_theory_set.begin(); - ptr_vector::iterator th_end = m_theory_set.end(); - for (; th_it != th_end; ++th_it) { - lbool theory_result = (*th_it)->validate_unsat_core(m_unsat_core); + for (theory* th : m_theory_set) { + lbool theory_result = th->validate_unsat_core(m_unsat_core); if (theory_result == l_undef) { return l_undef; } @@ -3296,10 +3294,8 @@ namespace smt { #ifndef _EXTERNAL_RELEASE if (m_fparams.m_display_installed_theories) { std::cout << "(theories"; - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - std::cout << " " << (*it)->get_name(); + for (theory* th : m_theory_set) { + std::cout << " " << th->get_name(); } std::cout << ")" << std::endl; } @@ -3316,17 +3312,13 @@ namespace smt { m_fparams.m_relevancy_lemma = false; // setup all the theories - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) - (*it)->setup(); + for (theory* th : m_theory_set) + th->setup(); } void context::add_theory_assumptions(expr_ref_vector & theory_assumptions) { - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - (*it)->add_theory_assumptions(theory_assumptions); + for (theory* th : m_theory_set) { + th->add_theory_assumptions(theory_assumptions); } } @@ -3342,18 +3334,7 @@ namespace smt { if (!check_preamble(reset_cancel)) return l_undef; - expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); - if (!already_did_theory_assumptions) { - add_theory_assumptions(all_assumptions); - } - - unsigned num_assumptions = all_assumptions.size(); - expr * const * assumptions = all_assumptions.c_ptr(); - - if (!validate_assumptions(num_assumptions, assumptions)) - return l_undef; TRACE("check_bug", tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";); - TRACE("unsat_core_bug", for (unsigned i = 0; i < num_assumptions; i++) { tout << mk_pp(assumptions[i], m_manager) << "\n";}); pop_to_base_lvl(); TRACE("before_search", display(tout);); SASSERT(at_base_level()); @@ -3363,6 +3344,18 @@ namespace smt { } else { setup_context(false); + expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); + if (!already_did_theory_assumptions) { + add_theory_assumptions(all_assumptions); + } + + unsigned num_assumptions = all_assumptions.size(); + expr * const * assumptions = all_assumptions.c_ptr(); + + if (!validate_assumptions(num_assumptions, assumptions)) + return l_undef; + TRACE("unsat_core_bug", tout << all_assumptions << "\n";); + internalize_assertions(); TRACE("after_internalize_assertions", display(tout);); if (m_asserted_formulas.inconsistent()) { @@ -3551,10 +3544,9 @@ namespace smt { pop_scope(m_scope_lvl - curr_lvl); SASSERT(at_search_level()); } - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end && !inconsistent(); ++it) - (*it)->restart_eh(); + for (theory* th : m_theory_set) { + if (!inconsistent()) th->restart_eh(); + } TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); if (!inconsistent()) { m_qmanager->restart_eh(); @@ -4070,10 +4062,7 @@ namespace smt { bool include = false; if (at_lbls) { // include if there is a label with the '@' sign. - buffer::const_iterator it = lbls.begin(); - buffer::const_iterator end = lbls.end(); - for (; it != end; ++it) { - symbol const & s = *it; + for (symbol const& s : lbls) { if (s.contains('@')) { include = true; break; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ffaee434f..c38ef4e4a 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -369,7 +369,7 @@ namespace smt { else { TRACE("internalize_bug", tout << "creating enode for #" << n->get_id() << "\n";); mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true, /* bool enode must be merged with true/false, since it is not in the context of a gate */ false /* CC is not enabled */ ); set_enode_flag(v, false); @@ -453,7 +453,7 @@ namespace smt { // must be associated with an enode. if (!e_internalized(n)) { mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true /* bool enode must be merged with true/false, since it is not in the context of a gate */, false /* CC is not enabled */); } @@ -739,7 +739,7 @@ namespace smt { app_ref eq1(mk_eq_atom(n, t), m_manager); app_ref eq2(mk_eq_atom(n, e), m_manager); mk_enode(n, - true /* supress arguments, I don't want to apply CC on ite terms */, + true /* suppress arguments, I don't want to apply CC on ite terms */, false /* it is a term, so it should not be merged with true/false */, false /* CC is not enabled */); internalize(c, true); @@ -797,7 +797,7 @@ namespace smt { } enode * e = mk_enode(n, - false, /* do not supress args */ + false, /* do not suppress args */ false, /* it is a term, so it should not be merged with true/false */ true); apply_sort_cnstr(n, e); @@ -1506,7 +1506,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_and_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to false, the the and-parent must be notified + // if one child is assigned to false, the and-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(~l, eh); } @@ -1518,7 +1518,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_or_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to true, the the or-parent must be notified + // if one child is assigned to true, the or-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(l, eh); } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 11202d58a..f443d671b 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -537,7 +537,7 @@ namespace smt { } } - // For each instantiation_set, reemove entries that do not evaluate to values. + // For each instantiation_set, remove entries that do not evaluate to values. void cleanup_instantiation_sets() { ptr_vector to_delete; for (node * curr : m_nodes) { @@ -735,7 +735,7 @@ namespace smt { } } // TBD: add support for the else of bitvectors. - // Idea: get the term t with the minimal interpreation and use t - 1. + // Idea: get the term t with the minimal interpretation and use t - 1. } n->set_else((*(elems.begin())).m_key); } @@ -955,7 +955,7 @@ namespace smt { if (elems.empty()) { // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts // (e.g., (Array S S) where S is uninterpreted). The problem is that these sorts do not have a fixed interpretation. - // Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value. + // Moreover, a model assigns an arbitrary interpretation to these sorts using "model_values" a model value. // If these module values "leak" inside the logical context, they may affect satisfiability. // sort * ns = n->get_sort(); @@ -1007,7 +1007,7 @@ namespace smt { This may happen because the evaluator uses model_completion. In the beginning of fix_model() we collected all f with partial interpretations. During the process of computing the - projections we used the evalutator with model_completion, + projections we used the evaluator with model_completion, and it may have fixed the "else" case of some partial interpretations. This is ok, because in the "limit" the "else" of the interpretation is irrelevant after the projections are applied. @@ -1570,7 +1570,7 @@ namespace smt { ast_manager & m = ctx->get_manager(); sort * s = q->get_decl_sort(num_vars - m_var_i - 1); if (m.is_uninterp(s)) { - // For uninterpreted sorst, we add all terms in the context. + // For uninterpreted sorts, we add all terms in the context. // See Section 4.1 in the paper "Complete Quantifier Instantiation" node * S_q_i = slv.get_uvar(q, m_var_i); ptr_vector::const_iterator it = ctx->begin_enodes(); @@ -1741,7 +1741,7 @@ namespace smt { if (has_quantifiers(q->get_expr())) { static bool displayed_flat_msg = false; if (!displayed_flat_msg) { - // [Leo]: This warning message is not usefult. + // [Leo]: This warning message is not useful. // warning_msg("For problems containing quantifiers, the model finding capabilities of Z3 work better when the formula does not contain nested quantifiers. You can use PULL_NESTED_QUANTIFIERS=true to eliminate nested quantifiers."); displayed_flat_msg = true; } @@ -2104,7 +2104,7 @@ namespace smt { } /** - \brief Process unintrepreted applications. + \brief Process uninterpreted applications. */ void process_u_app(app * t) { unsigned num_args = t->get_num_args(); @@ -2130,7 +2130,7 @@ namespace smt { /** \brief A term \c t is said to be a auf_select if - it is of ther form + it is of the form (select a i) Where: @@ -2151,7 +2151,7 @@ namespace smt { } /** - \brief Process intrepreted applications. + \brief Process interpreted applications. */ void process_i_app(app * t) { if (is_auf_select(t)) { @@ -2272,10 +2272,9 @@ namespace smt { process_literal(atom, pol == NEG); } - void process_or(app * n, polarity p) { - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - visit_formula(n->get_arg(i), p); + void process_and_or(app * n, polarity p) { + for (expr* arg : *n) + visit_formula(arg, p); } void process_ite(app * n, polarity p) { @@ -2306,13 +2305,13 @@ namespace smt { if (is_app(curr)) { if (to_app(curr)->get_family_id() == m_manager.get_basic_family_id() && m_manager.is_bool(curr)) { switch (static_cast(to_app(curr)->get_decl_kind())) { - case OP_AND: case OP_IMPLIES: case OP_XOR: UNREACHABLE(); // simplifier eliminated ANDs, IMPLIEs, and XORs break; case OP_OR: - process_or(to_app(curr), pol); + case OP_AND: + process_and_or(to_app(curr), pol); break; case OP_NOT: visit_formula(to_app(curr)->get_arg(0), neg(pol)); @@ -2513,7 +2512,7 @@ namespace smt { SASSERT(f_else != 0); // Remark: I can ignore the conditions of m because // I know the (partial) interpretation of f satisfied the ground part. - // MBQI will force extra instantiations if the the (partial) interpretation of f + // MBQI will force extra instantiations if the (partial) interpretation of f // does not satisfy the quantifier. // In all other cases the "else" of f will satisfy the quantifier. set_else_interp(f, f_else); @@ -2938,7 +2937,7 @@ namespace smt { } /** - \brief Use m_fs to set the interpreation of the function symbols that were used to satisfy the + \brief Use m_fs to set the interpretation of the function symbols that were used to satisfy the quantifiers in m_satisfied. */ void set_interp() { diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index d89f3f6a4..ad5f58e49 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -152,7 +152,7 @@ namespace smt { virtual bool mbqi_enabled(quantifier *q) const {return true;} /** - \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. + \brief Give a change to the plugin to adjust the interpretation of uninterpreted functions. It can basically change the "else" of each uninterpreted function. */ virtual void adjust_model(proto_model * m) = 0; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 631805b4d..bbc91e4c6 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -968,7 +968,7 @@ namespace smt { if (st.num_theories() == 2 && st.has_uf() && is_arith(st)) { if (!st.m_has_real) setup_QF_UFLIA(st); - else if (!st.m_has_int) + else if (!st.m_has_int && st.m_num_non_linear == 0) setup_QF_UFLRA(); else setup_unknown(); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 806b2a05b..6794ca3ac 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -660,7 +660,7 @@ namespace smt { satisfy their respective constraints. However, when they do that the may create inconsistencies in the other modules. I use m_liberal_final_check to avoid infinite - loops where the modules keep changing the assigment and no + loops where the modules keep changing the assignment and no progress is made. If m_liberal_final_check is set to false, these modules will avoid mutating the assignment to satisfy constraints. diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 230b6de77..87b811e8f 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -711,6 +711,7 @@ namespace smt { if (ctx.is_relevant(get_enode(*it)) && !check_monomial_assignment(*it, computed_epsilon)) { TRACE("non_linear_failed", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(*it), get_manager()) << "\n"; display_var(tout, *it);); + return false; } } diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 67fe5a572..997698411 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -526,7 +526,7 @@ namespace smt { } } } - pp.display(out, m.mk_true()); + pp.display_smt2(out, m.mk_true()); } template diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 292d2ab0d..21b66d3a0 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1916,7 +1916,7 @@ namespace smt { lp::var_index vi = m_theory_var2var_index[v]; SASSERT(m_solver->is_term(vi)); lp::lar_term const& term = m_solver->get_term(vi); - for (auto const coeff : term.m_coeffs) { + for (auto const& coeff : term.m_coeffs) { lp::var_index wi = coeff.first; lp::constraint_index ci; rational value; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ca6ab048c..f91685d43 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -397,15 +397,13 @@ bool theory_seq::branch_binary_variable(eq const& e) { expr_ref Y1(mk_skolem(symbol("seq.left"), x, y), m); expr_ref Y2(mk_skolem(symbol("seq.right"), x, y), m); ys.push_back(Y1); - expr_ref ysY1(m_util.str.mk_concat(ys.size(), ys.c_ptr()), m); - expr_ref xsE(m_util.str.mk_concat(xs.size(), xs.c_ptr()), m); - expr_ref Y1Y2(m_util.str.mk_concat(Y1, Y2), m); - literal_vector lits; - lits.push_back(~lit); + expr_ref ysY1(mk_concat(ys)); + expr_ref xsE(mk_concat(xs)); + expr_ref Y1Y2(mk_concat(Y1, Y2)); dependency* dep = e.dep(); - propagate_eq(dep, lits, x, ysY1, true); - propagate_eq(dep, lits, y, Y1Y2, true); - propagate_eq(dep, lits, Y2, xsE, true); + propagate_eq(dep, ~lit, x, ysY1); + propagate_eq(dep, ~lit, y, Y1Y2); + propagate_eq(dep, ~lit, Y2, xsE); } else { ctx.mark_as_relevant(lit); @@ -471,9 +469,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector literal lit = mk_eq(m_autil.mk_int(lX), m_util.str.mk_length(X), false); if (l_true == ctx.get_assignment(lit)) { expr_ref R(m_util.str.mk_concat(lX, units.c_ptr()), m); - literal_vector lits; - lits.push_back(lit); - propagate_eq(dep, lits, X, R, true); + propagate_eq(dep, lit, X, R); TRACE("seq", tout << "propagate " << mk_pp(X, m) << " " << R << "\n";); } else { @@ -506,11 +502,10 @@ bool theory_seq::branch_variable_mb() { for (unsigned j = 0; j < len2.size(); ++j) l2 += len2[j]; if (l1 != l2) { TRACE("seq", tout << "lengths are not compatible\n";); - expr_ref l = mk_concat(e.ls().size(), e.ls().c_ptr()); - expr_ref r = mk_concat(e.rs().size(), e.rs().c_ptr()); + expr_ref l = mk_concat(e.ls()); + expr_ref r = mk_concat(e.rs()); expr_ref lnl(m_util.str.mk_length(l), m), lnr(m_util.str.mk_length(r), m); - literal_vector lits; - propagate_eq(e.dep(), lits, lnl, lnr, false); + propagate_eq(e.dep(), lnl, lnr, false); change = true; continue; } @@ -626,8 +621,8 @@ bool theory_seq::split_lengths(dependency* dep, SASSERT(is_var(Y)); expr_ref Y1(mk_skolem(symbol("seq.left"), X, b, Y), m); expr_ref Y2(mk_skolem(symbol("seq.right"), X, b, Y), m); - expr_ref bY1(m_util.str.mk_concat(b, Y1), m); - expr_ref Y1Y2(m_util.str.mk_concat(Y1, Y2), m); + expr_ref bY1 = mk_concat(b, Y1); + expr_ref Y1Y2 = mk_concat(Y1, Y2); propagate_eq(dep, lits, X, bY1, true); propagate_eq(dep, lits, Y, Y1Y2, true); } @@ -1317,6 +1312,18 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { enforce_length_coherence(n1, n2); } +void theory_seq::propagate_eq(dependency* dep, expr* e1, expr* e2, bool add_eq) { + literal_vector lits; + propagate_eq(dep, lits, e1, e2, add_eq); +} + +void theory_seq::propagate_eq(dependency* dep, literal lit, expr* e1, expr* e2, bool add_to_eqs) { + literal_vector lits; + lits.push_back(lit); + propagate_eq(dep, lits, e1, e2, add_to_eqs); +} + + void theory_seq::enforce_length_coherence(enode* n1, enode* n2) { expr* o1 = n1->get_owner(); expr* o2 = n2->get_owner(); @@ -1662,19 +1669,18 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect } SASSERT(0 < l1 && l1 < ls.size()); SASSERT(0 < r1 && r1 < rs.size()); - expr_ref l(m_util.str.mk_concat(l1, ls1), m); - expr_ref r(m_util.str.mk_concat(r1, rs1), m); + expr_ref l = mk_concat(l1, ls1); + expr_ref r = mk_concat(r1, rs1); expr_ref lenl(m_util.str.mk_length(l), m); expr_ref lenr(m_util.str.mk_length(r), m); literal lit = mk_eq(lenl, lenr, false); if (ctx.get_assignment(lit) == l_true) { - literal_vector lits; expr_ref_vector lhs(m), rhs(m); lhs.append(l2, ls2); rhs.append(r2, rs2); deps = mk_join(deps, lit); m_eqs.push_back(eq(m_eq_id++, lhs, rhs, deps)); - propagate_eq(deps, lits, l, r, true); + propagate_eq(deps, l, r, true); TRACE("seq", tout << "propagate eq\nlhs: " << lhs << "\nrhs: " << rhs << "\n";); return true; } @@ -3212,9 +3218,10 @@ void theory_seq::add_indexof_axiom(expr* i) { literal t_eq_empty = mk_eq_empty(t); // |t| = 0 => |s| = 0 or indexof(t,s,offset) = -1 - // ~contains(t,s) => indexof(t,s,offset) = -1 + // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); +// add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { @@ -3227,6 +3234,7 @@ void theory_seq::add_indexof_axiom(expr* i) { add_axiom(~s_eq_empty, i_eq_0); add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy)); add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false)); + add_axiom(~cnt, mk_literal(m_autil.mk_ge(i, zero))); tightest_prefix(s, x); } else { @@ -3661,7 +3669,6 @@ void theory_seq::add_extract_axiom(expr* e) { literal ls_le_i = mk_simplified_literal(m_autil.mk_le(mk_sub(i, ls), zero)); literal li_ge_ls = mk_simplified_literal(m_autil.mk_ge(ls_minus_i_l, zero)); literal l_ge_zero = mk_simplified_literal(m_autil.mk_ge(l, zero)); - literal l_le_zero = mk_simplified_literal(m_autil.mk_le(l, zero)); literal ls_le_0 = mk_simplified_literal(m_autil.mk_le(ls, zero)); add_axiom(~i_ge_0, ~ls_le_i, mk_seq_eq(xey, s)); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index d4686c835..46f803f5b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -410,6 +410,8 @@ namespace smt { expr_ref mk_empty(sort* s) { return expr_ref(m_util.str.mk_empty(s), m); } expr_ref mk_concat(unsigned n, expr*const* es) { return expr_ref(m_util.str.mk_concat(n, es), m); } expr_ref mk_concat(expr_ref_vector const& es, sort* s) { if (es.empty()) return mk_empty(s); return mk_concat(es.size(), es.c_ptr()); } + expr_ref mk_concat(expr_ref_vector const& es) { SASSERT(!es.empty()); return mk_concat(es.size(), es.c_ptr()); } + expr_ref mk_concat(ptr_vector const& es) { SASSERT(!es.empty()); return mk_concat(es.size(), es.c_ptr()); } expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(m_util.str.mk_concat(e1, e2), m); } expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(m_util.str.mk_concat(e1, e2, e3), m); } bool solve_nqs(unsigned i); @@ -436,7 +438,9 @@ namespace smt { void propagate_lit(dependency* dep, unsigned n, literal const* lits, literal lit); void propagate_eq(dependency* dep, enode* n1, enode* n2); void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs); - void propagate_eq(dependency* dep, literal_vector const& lits, expr* e1, expr* e2, bool add_to_eqs); + void propagate_eq(dependency* dep, literal_vector const& lits, expr* e1, expr* e2, bool add_to_eqs = true); + void propagate_eq(dependency* dep, expr* e1, expr* e2, bool add_to_eqs = true); + void propagate_eq(dependency* dep, literal lit, expr* e1, expr* e2, bool add_to_eqs = true); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); u_map m_branch_start; diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 04eb86fe4..9ced6d186 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1474,7 +1474,7 @@ namespace smt { // pos < strlen(base) // --> pos + -1*strlen(base) < 0 argumentsValid_terms.push_back(mk_not(m, m_autil.mk_ge( - m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)), + m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, mk_strlen(substrBase))), zero))); // len >= 0 diff --git a/src/tactic/arith/purify_arith_tactic.h b/src/tactic/arith/purify_arith_tactic.h index bbb62710c..44b4f9b58 100644 --- a/src/tactic/arith/purify_arith_tactic.h +++ b/src/tactic/arith/purify_arith_tactic.h @@ -16,7 +16,7 @@ Abstract: Remarks: - The semantics of division by zero is not specified. Thus, uninterpreted functions are used. An ExRCF procedure may - treat the unintepreted function applications as fresh + treat the uninterpreted function applications as fresh constants. Then, in any model produced by this procedure, the interpretation for division by zero must be checked. diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 65d474182..5df523ff7 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -44,6 +44,7 @@ class solve_eqs_tactic : public tactic { expr_sparse_mark m_candidate_set; ptr_vector m_candidates; ptr_vector m_vars; + expr_sparse_mark m_nonzero; ptr_vector m_ordered_vars; bool m_produce_proofs; bool m_produce_unsat_cores; @@ -55,8 +56,7 @@ class solve_eqs_tactic : public tactic { m_r_owner(r == 0 || owner), m_a_util(m), m_num_steps(0), - m_num_eliminated_vars(0) - { + m_num_eliminated_vars(0) { updt_params(p); if (m_r == 0) m_r = mk_default_expr_replacer(m); @@ -78,7 +78,7 @@ class solve_eqs_tactic : public tactic { void checkpoint() { if (m().canceled()) throw tactic_exception(m().limit().get_cancel_msg()); - cooperate("solve-eqs"); + cooperate("solve-eqs"); } // Check if the number of occurrences of t is below the specified threshold :solve-eqs-max-occs @@ -106,7 +106,8 @@ class solve_eqs_tactic : public tactic { } } bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { - if (trivial_solve1(lhs, rhs, var, def, pr)) return true; + if (trivial_solve1(lhs, rhs, var, def, pr)) + return true; if (trivial_solve1(rhs, lhs, var, def, pr)) { if (m_produce_proofs) { pr = m().mk_commutativity(m().mk_eq(lhs, rhs)); @@ -187,6 +188,77 @@ class solve_eqs_tactic : public tactic { } return false; } + + void add_pos(expr* f) { + expr* lhs = nullptr, *rhs = nullptr; + rational val; + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_not(f, f)) { + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_eq(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_zero()) { + m_nonzero.mark(lhs); + } + } + } + + bool is_nonzero(expr* e) { + return m_nonzero.is_marked(e); + } + + bool isolate_var(app* arg, app_ref& var, expr_ref& div, unsigned i, app* lhs, expr* rhs) { + if (!m_a_util.is_mul(arg)) return false; + unsigned n = arg->get_num_args(); + for (unsigned j = 0; j < n; ++j) { + expr* e = arg->get_arg(j); + bool ok = is_uninterp_const(e) && check_occs(e) && !occurs(e, rhs) && !occurs_except(e, lhs, i); + if (!ok) continue; + var = to_app(e); + for (unsigned k = 0; ok && k < n; ++k) { + expr* arg_k = arg->get_arg(k); + ok = k == j || (!occurs(var, arg_k) && is_nonzero(arg_k)); + } + if (!ok) continue; + ptr_vector args; + for (unsigned k = 0; k < n; ++k) { + if (k != j) args.push_back(arg->get_arg(k)); + } + div = m_a_util.mk_mul(args.size(), args.c_ptr()); + return true; + } + return false; + } + + bool solve_nl(app * lhs, expr * rhs, expr* eq, app_ref& var, expr_ref & def, proof_ref & pr) { + SASSERT(m_a_util.is_add(lhs)); + if (m_a_util.is_int(lhs)) return false; + unsigned num = lhs->get_num_args(); + expr_ref div(m()); + for (unsigned i = 0; i < num; i++) { + expr * arg = lhs->get_arg(i); + if (is_app(arg) && isolate_var(to_app(arg), var, div, i, lhs, rhs)) { + ptr_vector args; + for (unsigned k = 0; k < num; ++k) { + if (k != i) args.push_back(lhs->get_arg(k)); + } + def = m_a_util.mk_sub(rhs, m_a_util.mk_add(args.size(), args.c_ptr())); + def = m_a_util.mk_div(def, div); + if (m_produce_proofs) + pr = m().mk_rewrite(eq, m().mk_eq(var, def)); + return true; + } + } + return false; + } bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { SASSERT(m_a_util.is_add(lhs)); @@ -204,7 +276,8 @@ class solve_eqs_tactic : public tactic { break; } else if (m_a_util.is_mul(arg, a, v) && - is_uninterp_const(v) && !m_candidate_vars.is_marked(v) && + is_uninterp_const(v) && + !m_candidate_vars.is_marked(v) && m_a_util.is_numeral(a, a_val) && !a_val.is_zero() && (!is_int || a_val.is_minus_one()) && @@ -252,16 +325,20 @@ class solve_eqs_tactic : public tactic { return (m_a_util.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, def, pr)) || (m_a_util.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, def, pr)); +#if 0 + // better done inside of nlsat + (m_a_util.is_add(lhs) && solve_nl(to_app(lhs), rhs, eq, var, def, pr)) || + (m_a_util.is_add(rhs) && solve_nl(to_app(rhs), lhs, eq, var, def, pr)); +#endif } bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) { - if (m().is_eq(f)) { - if (trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr)) + expr* arg1 = 0, *arg2 = 0; + if (m().is_eq(f, arg1, arg2)) { + if (trivial_solve(arg1, arg2, var, def, pr)) return true; if (m_theory_solver) { - expr * lhs = to_app(f)->get_arg(0); - expr * rhs = to_app(f)->get_arg(1); - if (solve_arith(lhs, rhs, f, var, def, pr)) + if (solve_arith(arg1, arg2, f, var, def, pr)) return true; } return false; @@ -321,11 +398,14 @@ class solve_eqs_tactic : public tactic { m_candidate_set.reset(); m_candidates.reset(); m_vars.reset(); - + m_nonzero.reset(); app_ref var(m()); expr_ref def(m()); proof_ref pr(m()); unsigned size = g.size(); + for (unsigned idx = 0; idx < size; idx++) { + add_pos(g.form(idx)); + } for (unsigned idx = 0; idx < size; idx++) { checkpoint(); expr * f = g.form(idx); @@ -347,10 +427,8 @@ class solve_eqs_tactic : public tactic { TRACE("solve_eqs", tout << "candidate vars:\n"; - ptr_vector::iterator it = m_vars.begin(); - ptr_vector::iterator end = m_vars.end(); - for (; it != end; ++it) { - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_vars) { + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); } @@ -374,12 +452,9 @@ class solve_eqs_tactic : public tactic { typedef std::pair frame; svector todo; - ptr_vector::const_iterator it = m_vars.begin(); - ptr_vector::const_iterator end = m_vars.end(); - unsigned num; - for (; it != end; ++it) { + unsigned num = 0; + for (app* v : m_vars) { checkpoint(); - app * v = *it; if (!m_candidate_vars.is_marked(v)) continue; todo.push_back(frame(v, 0)); @@ -483,20 +558,19 @@ class solve_eqs_tactic : public tactic { } // cleanup - it = m_vars.begin(); - for (unsigned idx = 0; it != end; ++it, ++idx) { - if (!m_candidate_vars.is_marked(*it)) { + unsigned idx = 0; + for (expr* v : m_vars) { + if (!m_candidate_vars.is_marked(v)) { m_candidate_set.mark(m_candidates[idx], false); } + ++idx; } TRACE("solve_eqs", tout << "ordered vars:\n"; - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - SASSERT(m_candidate_vars.is_marked(*it)); - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_ordered_vars) { + SASSERT(m_candidate_vars.is_marked(v)); + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); m_candidate_vars.reset(); @@ -609,10 +683,7 @@ class solve_eqs_tactic : public tactic { if (m_produce_models) { if (mc.get() == 0) mc = alloc(gmc, m()); - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - app * v = *it; + for (app* v : m_ordered_vars) { expr * def = 0; proof * pr; expr_dependency * dep; diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 420cb961a..09052869b 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -41,8 +41,8 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_qflra_probe(), mk_qflra_tactic(m), cond(mk_is_qfnra_probe(), mk_qfnra_tactic(m), cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), - cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_lira_probe(), mk_lira_tactic(m, p), + cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), mk_smt_tactic()))))))))))), diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index de542f3c4..23ae179e2 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -24,7 +24,6 @@ Notes: #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "smt/tactic/smt_tactic.h" -// include"mip_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" #include "tactic/arith/lia2pb_tactic.h" diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 3fb733ca4..d967660ce 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -26,8 +26,10 @@ Notes: #include "tactic/bv/max_bv_sharing_tactic.h" #include "sat/tactic/sat_tactic.h" #include "tactic/arith/nla2bv_tactic.h" +#include "tactic/arith/elim01_tactic.h" #include "tactic/core/ctx_simplify_tactic.h" #include "tactic/core/cofactor_term_ite_tactic.h" +#include "nlsat/tactic/qfnra_nlsat_tactic.h" static tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { params_ref p = p_ref; @@ -61,8 +63,6 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { ctx_simp_p.set_uint("max_depth", 30); ctx_simp_p.set_uint("max_steps", 5000000); - params_ref simp_p = p_ref; - simp_p.set_bool("hoist_mul", true); params_ref elim_p = p_ref; elim_p.set_uint("max_memory",20); @@ -73,21 +73,46 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), using_params(mk_simplify_tactic(m), pull_ite_p), mk_elim_uncnstr_tactic(m), - skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p)), - using_params(mk_simplify_tactic(m), simp_p)); + mk_elim01_tactic(m), + skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p))); } static tactic * mk_qfnia_sat_solver(ast_manager & m, params_ref const & p) { params_ref nia2sat_p = p; - nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + params_ref simp_p = p; + simp_p.set_bool("hoist_mul", true); // hoist multipliers to create smaller circuits. - return and_then(mk_nla2bv_tactic(m, nia2sat_p), + return and_then(using_params(mk_simplify_tactic(m), simp_p), + mk_nla2bv_tactic(m, nia2sat_p), mk_qfnia_bv_solver(m, p), mk_fail_if_undecided_tactic()); } +static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { + params_ref nia2sat_p = p; + nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + params_ref simp_p = p; + simp_p.set_bool("som", true); // expand into sums of monomials + simp_p.set_bool("factor", false); + + + return and_then(using_params(mk_simplify_tactic(m), simp_p), + try_for(mk_qfnra_nlsat_tactic(m, simp_p), 3000), + mk_fail_if_undecided_tactic()); +} + +static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { + params_ref simp_p = p; + simp_p.set_bool("som", true); // expand into sums of monomials + return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()); +} + tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { + return and_then(mk_qfnia_premable(m, p), or_else(mk_qfnia_sat_solver(m, p), - mk_smt_tactic())); + try_for(mk_qfnia_smt_solver(m, p), 2000), + mk_qfnia_nlsat_solver(m, p), + mk_qfnia_smt_solver(m, p))); } diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index 63c09c19c..cc01950a2 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -33,7 +33,9 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne } tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { - params_ref p1 = p; + params_ref p0 = p; + p0.set_bool("inline_vars", true); + params_ref p1 = p; p1.set_uint("seed", 11); p1.set_bool("factor", false); params_ref p2 = p; @@ -42,7 +44,7 @@ tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { return and_then(mk_simplify_tactic(m, p), mk_propagate_values_tactic(m, p), - or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000), + or_else(try_for(mk_qfnra_nlsat_tactic(m, p0), 5000), try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), mk_qfnra_sat_solver(m, p, 4), and_then(try_for(mk_smt_tactic(), 5000), mk_fail_if_undecided_tactic()), diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 400089a0c..8438d1a32 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -24,7 +24,6 @@ Revision History: #include "qe/qe_tactic.h" #include "qe/qe_lite.h" #include "qe/qsat.h" -#include "qe/nlqsat.h" #include "tactic/core/ctx_simplify_tactic.h" #include "smt/tactic/smt_tactic.h" #include "tactic/core/elim_term_ite_tactic.h" diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index 1e13f4fa4..af9888751 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -74,7 +74,7 @@ each offset is a different "variable bank". A pair (expr, offset) is essentially where every variable in expr is assumed to be from the "bank" offset. The class substitution (in substitution.h) manages offsets for us. -The class matcher (in matcher.h) can be use to test whether an expression is an instance of another one. +The class matcher (in matcher.h) can be used to test whether an expression is an instance of another one. Finally, there is the problem when we have N demodulators (where N is big), and a big formula, and we want to traverse the formula only once looking for opportunities for applying these N demodulators. diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index f1b20ba8e..e52bfbc1a 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -40,10 +40,10 @@ void tst_expr_arith(unsigned num_files) { pp.set_logic(symbol("QF_AUFLIA")); std::ostringstream buffer; - buffer << "random_arith_" << i << ".smt"; + buffer << "random_arith_" << i << ".smt2"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); - pp.display(file, e.get()); + pp.display_smt2(file, e.get()); file.close(); } @@ -83,10 +83,10 @@ void tst_expr_rand(unsigned num_files) { pp.set_logic(symbol("QF_AUFBV")); std::ostringstream buffer; - buffer << "random_bv_" << i << ".smt"; + buffer << "random_bv_" << i << ".smt2"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); - pp.display(file, e.get()); + pp.display_smt2(file, e.get()); file.close(); } diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index ecf73843f..19add1fab 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -272,7 +272,7 @@ static void tst4() { static void tst5() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -330,7 +330,7 @@ static nlsat::literal mk_eq(nlsat::solver& s, nlsat::poly* p) { static void tst6() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -390,7 +390,7 @@ static void tst6() { static void tst7() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); nlsat::pmanager & pm = s.pm(); nlsat::var x0, x1, x2, a, b, c, d; a = s.mk_var(false); @@ -443,7 +443,7 @@ static void tst7() { static void tst8() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -492,7 +492,7 @@ static void tst8() { static void tst9() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -624,7 +624,7 @@ static bool satisfies_root(nlsat::solver& s, nlsat::atom::kind k, nlsat::poly* p static void tst10() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index 3674e6b70..12fca706d 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -8,8 +8,6 @@ Copyright (c) 2015 Microsoft Corporation #include "smt/params/smt_params.h" #include "qe/qe.h" #include "ast/ast_pp.h" -#include "parsers/smt/smtlib.h" -#include "parsers/smt/smtparser.h" #include "util/lbool.h" #include #include "ast/reg_decl_plugins.h" @@ -54,6 +52,9 @@ static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char cons static void test_formula(lbool expected_outcome, char const* fml) { ast_manager m; reg_decl_plugins(m); + // No-op requires SMTLIB2 + +#if 0 scoped_ptr parser = smtlib::parser::create(m); parser->initialize_smtlib(); @@ -73,8 +74,10 @@ static void test_formula(lbool expected_outcome, char const* fml) { for (; it != end; ++it) { test_qe(m, expected_outcome, *it, 0); } +#endif } + void tst_quant_elim() { disable_debug("heap"); diff --git a/src/util/container_util.h b/src/util/container_util.h index e114c87b9..e68ab7199 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -29,7 +29,7 @@ Revision History: // ----------------------------------- template - void set_intersection(Set1 & tgt, const Set2 & src) { +void set_intersection(Set1 & tgt, const Set2 & src) { svector to_remove; for (auto const& itm : tgt) if (!src.contains(itm)) diff --git a/src/util/file_path.h b/src/util/file_path.h new file mode 100644 index 000000000..c34c8b408 --- /dev/null +++ b/src/util/file_path.h @@ -0,0 +1,39 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + file_path.h + +Abstract: + + File path functions. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#ifndef FILE_PATH_H_ +#define FILE_PATH_H_ +#include + +inline char const * get_extension(char const * file_name) { + if (file_name == 0) + return 0; + char const * last_dot = 0; + for (;;) { + char const * tmp = strchr(file_name, '.'); + if (tmp == 0) { + return last_dot; + } + last_dot = tmp + 1; + file_name = last_dot; + } +} + +#endif /* FILE_PATH_H_ */ + + diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index 4ebe63613..a8a743a71 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -38,10 +38,10 @@ template class numeric_traits {}; template <> class numeric_traits { public: static bool precise() { return true; } - static unsigned const zero() { return 0; } - static unsigned const one() { return 1; } + static unsigned zero() { return 0; } + static unsigned one() { return 1; } static bool is_zero(unsigned v) { return v == 0; } - static double const get_double(unsigned const & d) { return d; } + static double get_double(unsigned const & d) { return d; } }; template <> class numeric_traits { @@ -66,7 +66,7 @@ template <> class numeric_traits { static rational const & zero() { return rational::zero(); } static rational const & one() { return rational::one(); } static bool is_zero(const rational & v) { return v.is_zero(); } - static double const get_double(const rational & d) { return d.get_double();} + static double get_double(const rational & d) { return d.get_double();} static rational log(rational const& r) { UNREACHABLE(); return r; } static rational from_string(std::string const & str) { return rational(str.c_str()); } static bool is_pos(const rational & d) {return d.is_pos();} diff --git a/src/util/obj_ref_hashtable.h b/src/util/obj_ref_hashtable.h new file mode 100644 index 000000000..3d6bbf883 --- /dev/null +++ b/src/util/obj_ref_hashtable.h @@ -0,0 +1,117 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + obj_ref_hashtable.h + +Abstract: + + corresponding obj_map with reference count managment. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-12-8 + +Revision History: + +--*/ +#ifndef OBJ_REF_HASHTABLE_H_ +#define OBJ_REF_HASHTABLE_H_ + +#include "util/obj_hashtable.h" + +template +class obj_ref_map { + M& m; + obj_map m_table; +public: + typedef typename obj_map iterator; + typedef Key key; + typedef Value value; + typedef typename obj_map::key_data key_data; + typedef typename obj_map::obj_map_entry obj_map_entry; + + obj_ref_map(M& m):m(m) {} + + ~obj_ref_map() { reset(); } + + void reset() { + for (auto& kv : m_table) { + m.dec_ref(kv.m_key); + } + m_table.reset(); + } + + void finalize() { + reset(); + m_table.finalize(); + } + + bool empty() const { return m_table.empty(); } + + unsigned size() const { return m_table.size(); } + + unsigned capacity() const { return m_table.capacity(); } + + iterator begin() const { return m_table.begin(); } + + iterator end() const { return m_table.end(); } + + void insert(Key * const k, Value const & v) { + if (!m_table.contains(k)) m.inc_ref(k); + m_table.insert(k, v); + } + + void insert(Key * const k, Value && v) { + if (!m_table.contains(k)) m.inc_ref(k); + m_table.insert(k, v); + } + + key_data const & insert_if_not_there(Key * k, Value const & v) { + if (!m_table.contains(k)) m.inc_ref(k); + return m_table.insert_if_not_there(k, v); + } + + obj_map_entry * insert_if_not_there2(Key * k, Value const & v) { + if (!m_table.contains(k)) m.inc_ref(k); + return m_table.insert_if_not_there2(k, v); + } + + obj_map_entry * find_core(Key * k) const { return m_table.find_core(k); } + + bool find(Key * const k, Value & v) const { return m_table.find(k, v); } + + value const & find(key * k) const { return m_table.find(k); } + + value & find(key * k) { return m_table.find(k); } + + value const & operator[](key * k) const { return find(k); } + + value & operator[](key * k) { return find(k); } + + iterator find_iterator(Key * k) const { return m_table.find_iterator(k); } + + bool contains(Key * k) const { return m_table.contains(k); } + + void remove(Key * k) { + if (m_table.contains(k)) { + m_table.remove(k); + m.dec_ref(k); + } + } + + void erase(Key * k) { remove(k); } + + unsigned long long get_num_collision() const { return m_table.get_num_collision(); } + + void swap(obj_ref_map & other) { + m_table.swap(other.m_table); + } + + +}; + + +#endif /* OBJ_REF_HASHTABLE_H_ */ + diff --git a/src/util/stats.h b/src/util/stats.h index 0acc18f43..680f9c9df 100644 --- a/src/util/stats.h +++ b/src/util/stats.h @@ -29,7 +29,7 @@ inline void print_stat(std::ostream& out, char const* msg, unsigned num) { } inline void print_stat_f(std::ostream& out, char const* msg, float num) { - if (num > 0.0) { + if (num > 0.0f) { out << msg << num << "\n"; } }