summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml168
-rw-r--r--.travis.yml153
-rw-r--r--CMakeLists.txt6
-rw-r--r--README.md7
-rw-r--r--cmake/ConfigCompetition.cmake2
-rw-r--r--cmake/ConfigDebug.cmake2
-rw-r--r--cmake/ConfigProduction.cmake2
-rw-r--r--cmake/ConfigTesting.cmake2
-rwxr-xr-xconfigure.sh13
-rwxr-xr-xcontrib/get-antlr-3.46
-rw-r--r--examples/SimpleVC.java7
-rw-r--r--examples/SimpleVC.ml6
-rwxr-xr-xexamples/SimpleVC.php6
-rwxr-xr-xexamples/SimpleVC.pl6
-rwxr-xr-xexamples/SimpleVC.py6
-rwxr-xr-xexamples/SimpleVC.rb6
-rwxr-xr-xexamples/SimpleVC.tcl6
-rw-r--r--examples/api/bitvectors-new.cpp18
-rw-r--r--examples/api/bitvectors.cpp12
-rw-r--r--examples/api/combination-new.cpp7
-rw-r--r--examples/api/combination.cpp4
-rw-r--r--examples/api/extract-new.cpp6
-rw-r--r--examples/api/extract.cpp4
-rw-r--r--examples/api/helloworld-new.cpp2
-rw-r--r--examples/api/helloworld.cpp3
-rw-r--r--examples/api/java/BitVectors.java8
-rw-r--r--examples/api/java/Combination.java7
-rw-r--r--examples/api/java/HelloWorld.java2
-rw-r--r--examples/api/java/LinearArith.java5
-rw-r--r--examples/api/linear_arith-new.cpp6
-rw-r--r--examples/api/linear_arith.cpp5
-rwxr-xr-xexamples/api/python/bitvectors.py20
-rwxr-xr-xexamples/api/python/combination.py6
-rwxr-xr-xexamples/api/python/extract.py8
-rwxr-xr-xexamples/api/python/helloworld.py4
-rwxr-xr-xexamples/api/python/linear_arith.py6
-rwxr-xr-xexamples/api/python/sets.py6
-rw-r--r--examples/api/sets-new.cpp8
-rw-r--r--examples/api/sets.cpp6
-rw-r--r--examples/simple_vc_cxx.cpp6
-rw-r--r--src/CMakeLists.txt20
-rw-r--r--src/api/cvc4cpp.cpp96
-rw-r--r--src/api/cvc4cpp.h62
-rw-r--r--src/api/cvc4cppkind.h38
-rw-r--r--src/api/python/cvc4.pxd9
-rw-r--r--src/api/python/cvc4.pxi16
-rw-r--r--src/base/configuration.cpp4
-rw-r--r--src/base/configuration.h2
-rw-r--r--src/base/configuration_private.h6
-rw-r--r--src/bindings/java/CMakeLists.txt3
-rw-r--r--src/cvc4.i2
-rw-r--r--src/expr/CMakeLists.txt3
-rw-r--r--src/expr/expr_stream.h45
-rw-r--r--src/expr/expr_stream.i5
-rw-r--r--src/expr/metakind_template.h14
-rwxr-xr-xsrc/expr/mkmetakind16
-rw-r--r--src/expr/node_manager.cpp36
-rw-r--r--src/expr/node_manager.h56
-rw-r--r--src/expr/node_traversal.cpp150
-rw-r--r--src/expr/node_traversal.h131
-rw-r--r--src/main/command_executor.cpp9
-rw-r--r--src/main/command_executor.h7
-rw-r--r--src/main/driver_unified.cpp29
-rw-r--r--src/options/CMakeLists.txt1
-rw-r--r--src/options/arith_options.toml9
-rw-r--r--src/options/datatypes_options.toml9
-rw-r--r--src/options/idl_options.toml11
-rw-r--r--src/options/options.h33
-rw-r--r--src/options/options_handler.cpp32
-rw-r--r--src/options/options_handler.h6
-rw-r--r--src/options/options_public_functions.cpp4
-rw-r--r--src/options/options_template.cpp15
-rw-r--r--src/options/smt_options.toml21
-rw-r--r--src/options/theory_options.toml11
-rw-r--r--src/parser/cvc/Cvc.g17
-rw-r--r--src/parser/parser.cpp148
-rw-r--r--src/parser/parser.h80
-rw-r--r--src/parser/smt2/Smt2.g38
-rw-r--r--src/parser/smt2/smt2.cpp14
-rw-r--r--src/parser/smt2/smt2.h2
-rw-r--r--src/preprocessing/passes/bv_gauss.cpp5
-rw-r--r--src/preprocessing/passes/bv_gauss.h3
-rw-r--r--src/preprocessing/passes/bv_to_int.cpp23
-rw-r--r--src/preprocessing/passes/synth_rew_rules.cpp2
-rw-r--r--src/printer/cvc/cvc_printer.cpp5
-rw-r--r--src/printer/smt2/smt2_printer.cpp2
-rw-r--r--src/proof/proof_manager.cpp83
-rw-r--r--src/proof/proof_manager.h13
-rw-r--r--src/prop/minisat/core/Solver.cc13
-rw-r--r--src/prop/prop_engine.cpp25
-rw-r--r--src/prop/prop_engine.h5
-rw-r--r--src/prop/theory_proxy.cpp35
-rw-r--r--src/prop/theory_proxy.h20
-rw-r--r--src/smt/command.cpp2
-rw-r--r--src/smt/managed_ostreams.cpp27
-rw-r--r--src/smt/managed_ostreams.h21
-rw-r--r--src/smt/set_defaults.cpp1353
-rw-r--r--src/smt/set_defaults.h42
-rw-r--r--src/smt/smt_engine.cpp1362
-rw-r--r--src/smt/smt_engine.h102
-rw-r--r--src/theory/arith/arith_utilities.cpp6
-rw-r--r--src/theory/arith/arith_utilities.h3
-rw-r--r--src/theory/arith/nl_lemma_utils.cpp63
-rw-r--r--src/theory/arith/nl_lemma_utils.h52
-rw-r--r--src/theory/arith/nonlinear_extension.cpp1506
-rw-r--r--src/theory/arith/nonlinear_extension.h333
-rw-r--r--src/theory/arith/theory_arith.cpp6
-rw-r--r--src/theory/arith/theory_arith.h2
-rw-r--r--src/theory/arith/theory_arith_private.cpp39
-rw-r--r--src/theory/arith/transcendental_solver.cpp1475
-rw-r--r--src/theory/arith/transcendental_solver.h419
-rw-r--r--src/theory/arrays/theory_arrays.cpp6
-rw-r--r--src/theory/arrays/theory_arrays.h2
-rw-r--r--src/theory/booleans/theory_bool.cpp19
-rw-r--r--src/theory/booleans/theory_bool.h2
-rw-r--r--src/theory/builtin/theory_builtin.cpp37
-rw-r--r--src/theory/builtin/theory_builtin.h32
-rw-r--r--src/theory/bv/theory_bv.cpp5
-rw-r--r--src/theory/bv/theory_bv.h2
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp35
-rw-r--r--src/theory/datatypes/theory_datatypes.h2
-rw-r--r--src/theory/evaluator.cpp3
-rw-r--r--src/theory/evaluator.h2
-rw-r--r--src/theory/fp/theory_fp.cpp15
-rw-r--r--src/theory/fp/theory_fp.h2
-rw-r--r--src/theory/idl/idl_assertion.cpp213
-rw-r--r--src/theory/idl/idl_assertion.h91
-rw-r--r--src/theory/idl/idl_assertion_db.cpp59
-rw-r--r--src/theory/idl/idl_assertion_db.h86
-rw-r--r--src/theory/idl/idl_model.cpp74
-rw-r--r--src/theory/idl/idl_model.h84
-rw-r--r--src/theory/idl/kinds8
-rw-r--r--src/theory/idl/theory_idl.cpp156
-rw-r--r--src/theory/idl/theory_idl.h63
-rwxr-xr-xsrc/theory/mkrewriter4
-rwxr-xr-xsrc/theory/mktheorytraits6
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_cons.cpp15
-rw-r--r--src/theory/quantifiers/sygus_sampler.cpp3
-rw-r--r--src/theory/quantifiers/term_util.cpp5
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp6
-rw-r--r--src/theory/quantifiers/theory_quantifiers.h2
-rw-r--r--src/theory/rewriter.cpp6
-rw-r--r--src/theory/rewriter.h10
-rw-r--r--src/theory/rewriter_tables_template.h3
-rw-r--r--src/theory/sep/theory_sep.cpp6
-rw-r--r--src/theory/sep/theory_sep.h2
-rw-r--r--src/theory/sets/theory_sets.cpp7
-rw-r--r--src/theory/sets/theory_sets.h2
-rw-r--r--src/theory/strings/base_solver.cpp14
-rw-r--r--src/theory/strings/base_solver.h2
-rw-r--r--src/theory/strings/core_solver.cpp239
-rw-r--r--src/theory/strings/core_solver.h21
-rw-r--r--src/theory/strings/eqc_info.cpp19
-rw-r--r--src/theory/strings/extf_solver.cpp23
-rw-r--r--src/theory/strings/extf_solver.h6
-rw-r--r--src/theory/strings/infer_info.cpp56
-rw-r--r--src/theory/strings/infer_info.h115
-rw-r--r--src/theory/strings/inference_manager.cpp70
-rw-r--r--src/theory/strings/inference_manager.h34
-rw-r--r--src/theory/strings/kinds30
-rw-r--r--src/theory/strings/normal_form.cpp5
-rw-r--r--src/theory/strings/regexp_operation.cpp52
-rw-r--r--src/theory/strings/regexp_operation.h3
-rw-r--r--src/theory/strings/regexp_solver.cpp33
-rw-r--r--src/theory/strings/regexp_solver.h6
-rw-r--r--src/theory/strings/rewrites.cpp214
-rw-r--r--src/theory/strings/rewrites.h231
-rw-r--r--src/theory/strings/sequences_rewriter.cpp831
-rw-r--r--src/theory/strings/sequences_rewriter.h57
-rw-r--r--src/theory/strings/sequences_stats.cpp39
-rw-r--r--src/theory/strings/sequences_stats.h70
-rw-r--r--src/theory/strings/solver_state.cpp2
-rw-r--r--src/theory/strings/strings_fmf.cpp2
-rw-r--r--src/theory/strings/strings_rewriter.cpp53
-rw-r--r--src/theory/strings/strings_rewriter.h16
-rw-r--r--src/theory/strings/theory_strings.cpp82
-rw-r--r--src/theory/strings/theory_strings.h2
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp32
-rw-r--r--src/theory/strings/theory_strings_preprocess.h86
-rw-r--r--src/theory/strings/theory_strings_type_rules.h5
-rw-r--r--src/theory/strings/theory_strings_utils.cpp55
-rw-r--r--src/theory/strings/theory_strings_utils.h21
-rw-r--r--src/theory/strings/type_enumerator.cpp42
-rw-r--r--src/theory/strings/type_enumerator.h20
-rw-r--r--src/theory/strings/word.cpp25
-rw-r--r--src/theory/strings/word.h7
-rw-r--r--src/theory/theory.h6
-rw-r--r--src/theory/theory_engine.cpp14
-rw-r--r--src/theory/theory_engine.h9
-rw-r--r--src/theory/theory_model.cpp8
-rw-r--r--src/theory/theory_model.h3
-rw-r--r--src/theory/uf/theory_uf.cpp5
-rw-r--r--src/theory/uf/theory_uf.h2
-rw-r--r--src/util/CMakeLists.txt6
-rw-r--r--src/util/regexp.cpp491
-rw-r--r--src/util/regexp.h285
-rw-r--r--src/util/regexp.i21
-rw-r--r--src/util/result.cpp188
-rw-r--r--src/util/result.h38
-rw-r--r--src/util/result.i6
-rw-r--r--src/util/safe_print.h55
-rw-r--r--src/util/string.cpp485
-rw-r--r--src/util/string.h271
-rw-r--r--src/util/string.i25
-rw-r--r--test/regress/CMakeLists.txt12
-rw-r--r--test/regress/regress0/arith/arith.01.cvc2
-rw-r--r--test/regress/regress0/arith/arith.02.cvc2
-rw-r--r--test/regress/regress0/arith/arith.03.cvc2
-rw-r--r--test/regress/regress0/arith/bug549.cvc4
-rw-r--r--test/regress/regress0/arith/integers/arith-int-014.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-015.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-021.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-023.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-025.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-042.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-042.min.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-int-079.cvc2
-rw-r--r--test/regress/regress0/arith/integers/arith-interval.cvc2
-rw-r--r--test/regress/regress0/boolean-prec.cvc2
-rw-r--r--test/regress/regress0/bug310.cvc2
-rw-r--r--test/regress/regress0/bug32.cvc2
-rw-r--r--test/regress/regress0/bug322b.cvc6
-rw-r--r--test/regress/regress0/bug486.cvc4
-rw-r--r--test/regress/regress0/bv/bvcomp.cvc2
-rw-r--r--test/regress/regress0/bv/bvsimple.cvc2
-rw-r--r--test/regress/regress0/cvc-rerror-print.cvc4
-rw-r--r--test/regress/regress0/cvc3-bug15.cvc2
-rw-r--r--test/regress/regress0/cvc3.userdoc.01.cvc20
-rw-r--r--test/regress/regress0/cvc3.userdoc.02.cvc2
-rw-r--r--test/regress/regress0/cvc3.userdoc.03.cvc2
-rw-r--r--test/regress/regress0/cvc3.userdoc.04.cvc2
-rw-r--r--test/regress/regress0/cvc3.userdoc.05.cvc2
-rw-r--r--test/regress/regress0/cvc3.userdoc.06.cvc4
-rw-r--r--test/regress/regress0/datatypes/bug286.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype-dump.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype0.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype1.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype13.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype2.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype3.cvc2
-rw-r--r--test/regress/regress0/datatypes/datatype4.cvc2
-rw-r--r--test/regress/regress0/datatypes/empty_tuprec.cvc8
-rw-r--r--test/regress/regress0/datatypes/mutually-recursive.cvc2
-rw-r--r--test/regress/regress0/datatypes/rec1.cvc2
-rw-r--r--test/regress/regress0/datatypes/rec2.cvc2
-rw-r--r--test/regress/regress0/datatypes/rec4.cvc2
-rw-r--r--test/regress/regress0/datatypes/rewriter.cvc2
-rw-r--r--test/regress/regress0/datatypes/tuple-record-bug.cvc2
-rw-r--r--test/regress/regress0/datatypes/tuple.cvc2
-rw-r--r--test/regress/regress0/datatypes/typed_v10l30054.cvc2
-rw-r--r--test/regress/regress0/datatypes/typed_v1l80005.cvc2
-rw-r--r--test/regress/regress0/datatypes/typed_v2l30079.cvc2
-rw-r--r--test/regress/regress0/datatypes/typed_v3l20092.cvc2
-rw-r--r--test/regress/regress0/datatypes/typed_v5l30069.cvc2
-rw-r--r--test/regress/regress0/datatypes/v10l40099.cvc2
-rw-r--r--test/regress/regress0/datatypes/v2l40025.cvc2
-rw-r--r--test/regress/regress0/datatypes/v3l60006.cvc2
-rw-r--r--test/regress/regress0/datatypes/v5l30058.cvc2
-rw-r--r--test/regress/regress0/datatypes/wrong-sel-simp.cvc2
-rw-r--r--test/regress/regress0/fmf/bug-041417-set-options.cvc2
-rw-r--r--test/regress/regress0/let.cvc2
-rw-r--r--test/regress/regress0/logops.01.cvc2
-rw-r--r--test/regress/regress0/logops.02.cvc2
-rw-r--r--test/regress/regress0/logops.03.cvc2
-rw-r--r--test/regress/regress0/logops.04.cvc2
-rw-r--r--test/regress/regress0/logops.05.cvc2
-rw-r--r--test/regress/regress0/nl/ext-rew-aggr-test.smt22
-rw-r--r--test/regress/regress0/parser/choice.cvc10
-rw-r--r--test/regress/regress0/parser/choice.smt210
-rw-r--r--test/regress/regress0/precedence/and-not.cvc2
-rw-r--r--test/regress/regress0/precedence/and-xor.cvc2
-rw-r--r--test/regress/regress0/precedence/bool-cmp.cvc2
-rw-r--r--test/regress/regress0/precedence/cmp-plus.cvc2
-rw-r--r--test/regress/regress0/precedence/eq-fun.cvc2
-rw-r--r--test/regress/regress0/precedence/iff-assoc.cvc2
-rw-r--r--test/regress/regress0/precedence/iff-implies.cvc2
-rw-r--r--test/regress/regress0/precedence/implies-assoc.cvc2
-rw-r--r--test/regress/regress0/precedence/implies-iff.cvc2
-rw-r--r--test/regress/regress0/precedence/implies-or.cvc2
-rw-r--r--test/regress/regress0/precedence/not-and.cvc2
-rw-r--r--test/regress/regress0/precedence/not-eq.cvc2
-rw-r--r--test/regress/regress0/precedence/or-implies.cvc2
-rw-r--r--test/regress/regress0/precedence/or-xor.cvc2
-rw-r--r--test/regress/regress0/precedence/plus-mult.cvc2
-rw-r--r--test/regress/regress0/precedence/xor-and.cvc2
-rw-r--r--test/regress/regress0/precedence/xor-assoc.cvc2
-rw-r--r--test/regress/regress0/precedence/xor-or.cvc2
-rw-r--r--test/regress/regress0/preprocess/preprocess_00.cvc2
-rw-r--r--test/regress/regress0/preprocess/preprocess_02.cvc2
-rw-r--r--test/regress/regress0/preprocess/preprocess_06.cvc2
-rw-r--r--test/regress/regress0/preprocess/preprocess_13.cvc2
-rw-r--r--test/regress/regress0/printer/tuples_and_records.cvc2
-rw-r--r--test/regress/regress0/push-pop/bug233.cvc4
-rw-r--r--test/regress/regress0/push-pop/incremental-subst-bug.cvc14
-rw-r--r--test/regress/regress0/quantifiers/cegqi-nl-simp.cvc2
-rw-r--r--test/regress/regress0/sets/cvc-sample.cvc2
-rw-r--r--test/regress/regress0/simple.cvc2
-rw-r--r--test/regress/regress0/smallcnf.cvc2
-rw-r--r--test/regress/regress0/smtlib/issue4151.smt213
-rw-r--r--test/regress/regress0/smtlib/set-info-status.smt22
-rw-r--r--test/regress/regress0/strings/bug002.smt22
-rw-r--r--test/regress/regress0/strings/char-representations.smt222
-rw-r--r--test/regress/regress0/strings/gen-esc-seq.smt29
-rw-r--r--test/regress/regress0/strings/loop-wrong-sem.smt24
-rw-r--r--test/regress/regress0/strings/model-code-point.smt213
-rw-r--r--test/regress/regress0/strings/model-friendly.smt29
-rw-r--r--test/regress/regress0/strings/unicode-esc.smt232
-rw-r--r--test/regress/regress0/sygus/c100.sy4
-rw-r--r--test/regress/regress0/sygus/check-generic-red.sy3
-rw-r--r--test/regress/regress0/sygus/const-var-test.sy5
-rw-r--r--test/regress/regress0/sygus/sygus-uf.sy7
-rw-r--r--test/regress/regress0/test11.cvc2
-rw-r--r--test/regress/regress0/test9.cvc2
-rw-r--r--test/regress/regress0/uf/simple.01.cvc2
-rw-r--r--test/regress/regress0/uf/simple.02.cvc2
-rw-r--r--test/regress/regress0/uf/simple.03.cvc2
-rw-r--r--test/regress/regress0/uf/simple.04.cvc2
-rw-r--r--test/regress/regress0/uf20-03.cvc2
-rw-r--r--test/regress/regress0/wiki.01.cvc2
-rw-r--r--test/regress/regress0/wiki.02.cvc2
-rw-r--r--test/regress/regress0/wiki.03.cvc2
-rw-r--r--test/regress/regress0/wiki.04.cvc2
-rw-r--r--test/regress/regress0/wiki.05.cvc2
-rw-r--r--test/regress/regress0/wiki.06.cvc2
-rw-r--r--test/regress/regress0/wiki.07.cvc2
-rw-r--r--test/regress/regress0/wiki.08.cvc2
-rw-r--r--test/regress/regress0/wiki.09.cvc2
-rw-r--r--test/regress/regress0/wiki.10.cvc2
-rw-r--r--test/regress/regress0/wiki.11.cvc2
-rw-r--r--test/regress/regress0/wiki.12.cvc2
-rw-r--r--test/regress/regress0/wiki.13.cvc2
-rw-r--r--test/regress/regress0/wiki.14.cvc2
-rw-r--r--test/regress/regress0/wiki.15.cvc2
-rw-r--r--test/regress/regress0/wiki.16.cvc2
-rw-r--r--test/regress/regress0/wiki.17.cvc2
-rw-r--r--test/regress/regress0/wiki.18.cvc2
-rw-r--r--test/regress/regress0/wiki.19.cvc2
-rw-r--r--test/regress/regress0/wiki.20.cvc2
-rw-r--r--test/regress/regress0/wiki.21.cvc2
-rw-r--r--test/regress/regress1/arith/arith-brab-test.smt223
-rw-r--r--test/regress/regress1/arith/arith-int-001.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-002.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-003.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-004.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-005.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-006.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-007.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-008.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-009.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-010.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-011.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-012.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-013.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-016.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-017.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-018.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-019.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-020.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-022.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-024.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-026.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-027.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-028.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-029.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-030.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-031.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-032.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-033.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-034.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-035.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-036.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-037.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-038.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-039.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-040.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-041.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-043.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-044.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-045.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-046.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-047.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-048.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-049.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-050.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-051.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-052.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-053.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-054.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-055.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-056.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-057.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-058.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-059.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-060.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-061.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-062.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-063.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-064.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-065.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-066.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-067.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-068.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-069.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-070.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-071.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-072.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-073.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-074.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-075.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-076.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-077.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-078.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-080.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-081.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-082.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-083.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-084.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-085.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-086.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-087.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-088.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-089.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-090.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-091.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-092.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-093.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-094.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-095.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-096.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-097.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-099.cvc2
-rw-r--r--test/regress/regress1/arith/arith-int-100.cvc2
-rw-r--r--test/regress/regress1/arith/bug547.1.smt24
-rw-r--r--test/regress/regress1/boolean.cvc2
-rw-r--r--test/regress/regress1/fmf/fmf-strange-bounds.smt213
-rw-r--r--test/regress/regress1/fmf/ko-bound-set.cvc2
-rw-r--r--test/regress/regress1/hole6.cvc2
-rw-r--r--test/regress/regress1/quantifiers/set-choice-koikonomou.cvc2
-rw-r--r--test/regress/regress1/rr-verify/regex.sy9
-rw-r--r--test/regress/regress1/strings/bug686dd.smt24
-rw-r--r--test/regress/regress1/strings/pierre150331.smt22
-rw-r--r--test/regress/regress1/strings/reloop.smt28
-rw-r--r--test/regress/regress1/sygus/dt-test-ns.sy4
-rw-r--r--test/regress/regress1/sygus/hd-19-d1-prog-dup-op.sy18
-rw-r--r--test/regress/regress1/sygus/issue3461.sy7
-rw-r--r--test/regress/regress1/sygus/list-head-x.sy2
-rw-r--r--test/regress/regress1/sygus/max.sy4
-rw-r--r--test/regress/regress1/sygus/parity-si-rcons.sy3
-rw-r--r--test/regress/regress1/sygus/re-concat.sy8
-rw-r--r--test/regress/regress1/sygus/simple-regexp.sy50
-rw-r--r--test/regress/regress1/sygus/sygus-uf-ex.sy30
-rw-r--r--test/regress/regress1/test12.cvc60
-rw-r--r--test/regress/regress2/arith/arith-int-098.cvc2
-rw-r--r--test/regress/regress2/hole7.cvc2
-rw-r--r--test/regress/regress2/hole8.cvc2
-rw-r--r--test/regress/regress2/strings/range-perf.smt22
-rw-r--r--test/regress/regress2/sygus/issue4022-conjecture-gen.smt21
-rw-r--r--test/regress/regress2/typed_v1l50016-simp.cvc2
-rw-r--r--test/regress/regress3/hole9.cvc2
-rw-r--r--test/regress/regress4/hole10.cvc2
-rw-r--r--test/system/boilerplate.cpp4
-rw-r--r--test/system/statistics.cpp9
-rw-r--r--test/system/two_smt_engines.cpp6
-rw-r--r--test/unit/api/result_black.h48
-rw-r--r--test/unit/api/solver_black.h86
-rw-r--r--test/unit/expr/CMakeLists.txt1
-rw-r--r--test/unit/expr/node_traversal_black.h281
-rw-r--r--test/unit/preprocessing/pass_bv_gauss_white.h7
-rw-r--r--test/unit/theory/evaluator_white.h1
-rw-r--r--test/unit/theory/regexp_operation_black.h4
-rw-r--r--test/unit/theory/sequences_rewriter_white.h1
-rw-r--r--test/unit/theory/theory_black.h15
-rw-r--r--test/unit/theory/theory_bv_rewriter_white.h1
-rw-r--r--test/unit/theory/theory_engine_white.h144
-rw-r--r--test/unit/theory/theory_quantifiers_bv_instantiator_white.h1
-rw-r--r--test/unit/theory/theory_sets_type_enumerator_white.h22
-rw-r--r--test/unit/theory/theory_strings_skolem_cache_black.h22
-rw-r--r--test/unit/theory/theory_white.h7
-rw-r--r--test/unit/theory/type_enumerator_white.h17
481 files changed, 8749 insertions, 7266 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 000000000..705e0679d
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,168 @@
+on: [push, pull_request]
+name: CI
+
+jobs:
+ build:
+
+ strategy:
+ matrix:
+ os: [ubuntu-latest, macos-latest]
+ name: [
+ production,
+ production-clang,
+ debug,
+ debug-cln
+ ]
+
+ include:
+ - name: production
+ config: production --language-bindings=java --lfsc --python-bindings
+ cache-key: production
+ python-bindings: true
+ check-examples: true
+
+ - name: production-clang
+ config: production
+ cache-key: production-clang
+ check-examples: true
+ env: CC=clang CXX=clang++
+
+ - name: debug
+ config: debug --symfpu --lfsc --no-debug-symbols
+ cache-key: debug
+
+ - name: debug-cln
+ config: debug --symfpu --cln --gpl --no-debug-symbols --no-proofs
+ cache-key: debug-cln
+
+ name: ${{ matrix.os }}:${{ matrix.name }}
+ runs-on: ${{ matrix.os }}
+
+ steps:
+
+ - uses: actions/checkout@v2
+
+ - name: Install Packages
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y \
+ ccache \
+ cxxtest \
+ libcln-dev \
+ libgmp-dev \
+ swig3.0
+ python3 -m pip install toml
+ python3 -m pip install setuptools
+ echo "::add-path::/usr/lib/ccache"
+
+ - name: Install Packages (macOS)
+ if: runner.os == 'macOS'
+ run: |
+ brew install \
+ ccache \
+ cxxtest \
+ cln \
+ gmp \
+ swig
+ python3 -m pip install toml
+ python3 -m pip install setuptools
+ echo "::add-path::/usr/local/opt/ccache/libexec"
+
+ # Note: We install Cython with sudo since cmake can't find Cython otherwise.
+ - name: Install Cython
+ if: matrix.python-bindings && runner.os == 'Linux'
+ run: |
+ sudo python3 -m pip install \
+ Cython==0.29 --install-option="--no-cython-compile"
+
+ - name: Install Cython (macOS)
+ if: matrix.python-bindings && runner.os == 'macOS'
+ run: |
+ python3 -m pip install \
+ Cython==0.29 --install-option="--no-cython-compile"
+
+ - name: Restore Dependencies
+ id: restore-deps
+ uses: actions/cache@v1
+ with:
+ path: deps/install
+ key: ${{ runner.os }}-deps-${{ hashFiles('contrib/get-**') }}-${{ hashFiles('.github/workflows/ci.yml') }}
+
+ - name: Setup Dependencies
+ if: steps.restore-deps.outputs.cache-hit != 'true'
+ run: |
+ ./contrib/get-antlr-3.4
+ ./contrib/get-symfpu
+ ./contrib/get-cadical
+ ./contrib/get-cryptominisat
+ ./contrib/get-lfsc-checker
+
+ # GitHub actions currently does not support modifying an already existing
+ # cache. Hence, we create a new cache for each commit with key
+ # cache-${{ runner.os }}-${{ matrix.cache-key }}-${{ github.sha }}. This
+ # will result in an initial cache miss. However, restore-keys will search
+ # for the most recent cache with prefix
+ # cache-${{ runner.os }}-${{ matrix.cache-key }}-, and if found uses it as
+ # a base for the new cache.
+ - name: Restore ccache
+ id: cache
+ uses: actions/cache@v1
+ with:
+ path: ccache-dir
+ key: cache-${{ runner.os }}-${{ matrix.cache-key }}-${{ github.sha }}
+ restore-keys: cache-${{ runner.os }}-${{ matrix.cache-key }}-
+
+ - name: Configure ccache
+ run: |
+ ccache --set-config=cache_dir=${{ github.workspace }}/ccache-dir
+ ccache --set-config=compression=true
+ ccache --set-config=compression_level=6
+ ccache -M 500M
+ ccache -z
+
+ - name: Configure
+ run: |
+ ${{ matrix.env }} ./configure.sh ${{ matrix.config }} \
+ --python3 \
+ --prefix=$(pwd)/build/install \
+ --unit-testing
+
+ - name: Build
+ run: make -j2
+ working-directory: build
+
+ - name: ccache Statistics
+ run: ccache -s
+
+ - name: Run CTest
+ run: make -j2 check
+ env:
+ ARGS: --output-on-failure -LE regress[1-4]
+ CVC4_REGRESSION_ARGS: --no-early-exit
+ working-directory: build
+
+ - name: Install Check
+ run: |
+ make -j2 install
+ echo -e "#include <cvc4/api/cvc4cpp.h>\nint main() { CVC4::api::Solver s; return 0; }" > /tmp/test.cpp
+ g++ -std=c++11 /tmp/test.cpp -I install/include -L install/lib -lcvc4
+ working-directory: build
+
+ - name: Python Install Check
+ if: matrix.python-bindings
+ run: |
+ export PYTHONPATH="$PYTHONPATH:$(dirname $(find build/install/ -name "pycvc4" -type d))"
+ python3 -c "import pycvc4"
+
+ # Examples are built for non-symfpu builds
+ - name: Check Examples
+ if: matrix.check-examples && runner.os == 'Linux'
+ run: |
+ mkdir build
+ cd build
+ cmake .. -DCMAKE_PREFIX_PATH=$(pwd)/../../build/install/lib/cmake
+ make -j2
+ ctest -j2 --output-on-failure
+ working-directory: examples
+
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 8297813da..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,153 +0,0 @@
-language: cpp
-cache:
- - apt
- - ccache
-
-sudo: false
-dist: xenial
-
-env:
- global:
- - CCACHE_COMPRESS=1
-addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages: &common_deps
- - antlr3
- - cmake
- - cxxtest
- - junit4
- - libantlr3c-dev
- - libcln-dev
- - libgmp-dev
- - libhamcrest-java
- - openjdk-8-jdk
- - python3
- - python3-pip
- - python3-setuptools
- - swig3.0
-before_install:
- # Clang does not play nice with ccache (at least the versions offered by
- # Travis), use a workaround:
- # https://github.com/travis-ci/travis-ci/issues/5383#issuecomment-224630584
- - |
- if [ "$TRAVIS_OS_NAME" == "linux" ] && [ "$CXX" == "clang++" ]; then
- export CFLAGS="-Qunused-arguments"
- export CXXFLAGS="-Qunused-arguments"
- sudo ln -s $(which ccache) /usr/lib/ccache/clang
- sudo ln -s $(which ccache) /usr/lib/ccache/clang++
- fi
-before_script:
- export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
-script:
- - ccache -M 1G
- - ccache -z
- - ${CC} --version
- - ${CXX} --version
- - sudo ${TRAVIS_PYTHON} -m pip install toml
- - sudo ${TRAVIS_PYTHON} -m pip install Cython==0.29 --install-option="--no-cython-compile"
- - |
- echo "travis_fold:start:load_script"
- normal="$(echo -e '\033[0m')" red="$normal$(echo -e '\033[01;31m')" green="$normal$(echo -e '\033[01;32m')"
- configureCVC4() {
- echo "CVC4 config - $TRAVIS_CVC4_CONFIG";
- ./configure.sh --name=build --prefix=$(pwd)/build/install --unit-testing $TRAVIS_CVC4_CONFIG
- }
- error() {
- echo;
- echo "${red}${1}${normal}";
- echo;
- exit 1;
- }
- makeCheck() {
- (
- cd build
- make -j2 check ARGS='-LE regress[1-4]' CVC4_REGRESSION_ARGS='--no-early-exit' || error "BUILD/UNIT/SYSTEM/REGRESSION TEST FAILED"
- )
- }
- makeExamples() {
- (
- cd examples
- mkdir build
- cd build
- cmake .. -DCMAKE_PREFIX_PATH=$(pwd)/../../build/install/lib/cmake
- make -j2
- ctest -j2 --output-on-failure || error "RUNNING EXAMPLES FAILED"
- )
- }
- makeInstallCheck() {
- (
- cd build
- make install -j2
- echo -e "#include <cvc4/cvc4.h>\nint main() { CVC4::ExprManager em; return 0; }" > /tmp/test.cpp
- $CXX -std=c++11 /tmp/test.cpp -I install/include -L install/lib -lcvc4 -lcln || exit 1
- # set PYTHONPATH to include the directory containing pycvc4 module
- export PYTHONPATH=$PYTHONPATH:$(dirname $(find ./install/ -name "pycvc4" -type d))
- if [[ "$TRAVIS_CVC4_PYTHON_BINDINGS" == "yes" ]]; then
- $TRAVIS_PYTHON -c "import pycvc4" || exit 1
- fi
- )
- }
- run() {
- echo "travis_fold:start:$1"
- echo "Running $1"
- $1 || exit 1
- echo "travis_fold:end:$1"
- }
- [[ "$TRAVIS_CVC4_CONFIG" == *"symfpu"* ]] && CVC4_SYMFPU_BUILD="yes"
- [ -n "$CVC4_SYMFPU_BUILD" ] && run contrib/get-symfpu
- [ -n "$TRAVIS_CVC4" ] && [ -n "$TRAVIS_WITH_LFSC" ] && run contrib/get-lfsc-checker
- [ -n "$TRAVIS_CVC4" ] && run configureCVC4
- [ -n "$TRAVIS_CVC4" ] && run makeCheck
- [ -z "$CVC4_SYMFPU_BUILD" ] && run makeInstallCheck && run makeExamples
- [ -z "$TRAVIS_CVC4" ] && error "Unknown Travis-CI configuration"
- echo "travis_fold:end:load_script"
- - echo; echo "${green}EVERYTHING SEEMED TO PASS!${normal}"
- - ccache -s
-matrix:
- fast_finish: true
- include:
- # Test with GCC
- - compiler: gcc
- env:
- - TRAVIS_CVC4=yes
- - TRAVIS_WITH_LFSC=yes
- - TRAVIS_CVC4_PYTHON_BINDINGS=no
- - TRAVIS_CVC4_CONFIG="production --language-bindings=java --lfsc"
- - TRAVIS_PYTHON=python
- - compiler: gcc
- env:
- - TRAVIS_CVC4=yes
- - TRAVIS_WITH_LFSC=yes
- - TRAVIS_CVC4_PYTHON_BINDINGS=no
- - TRAVIS_CVC4_CONFIG="debug --symfpu --lfsc --no-debug-symbols"
- - TRAVIS_PYTHON=python
- # Test python bindings
- - compiler: gcc
- env:
- - TRAVIS_CVC4=yes
- - TRAVIS_WITH_LFSC=yes
- - TRAVIS_CVC4_PYTHON_BINDINGS=yes
- - TRAVIS_CVC4_CONFIG="production --python-bindings --python2"
- - TRAVIS_PYTHON=python
- - compiler: gcc
- env:
- - TRAVIS_CVC4=yes
- - TRAVIS_WITH_LFSC=yes
- - TRAVIS_CVC4_PYTHON_BINDINGS=yes
- - TRAVIS_CVC4_CONFIG="production --python-bindings --python3"
- - TRAVIS_PYTHON=python3
- #
- # Test with Clang
- - compiler: clang
- env:
- - TRAVIS_CVC4=yes
- - TRAVIS_WITH_LFSC=yes
- - TRAVIS_CVC4_PYTHON_BINDINGS=no
- - TRAVIS_CVC4_CONFIG="debug --symfpu --cln --gpl --no-debug-symbols --no-proofs"
- - TRAVIS_PYTHON=python
-notifications:
- email:
- on_success: change
- on_failure: always
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 945f71d36..c535890e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -121,7 +121,6 @@ cvc4_option(ENABLE_DEBUG_SYMBOLS "Enable debug symbols")
cvc4_option(ENABLE_DUMPING "Enable dumping")
cvc4_option(ENABLE_MUZZLE "Suppress ALL non-result output")
cvc4_option(ENABLE_PROOFS "Enable proof support")
-cvc4_option(ENABLE_REPLAY "Enable the replay feature")
cvc4_option(ENABLE_STATISTICS "Enable statistics")
cvc4_option(ENABLE_TRACING "Enable tracing")
cvc4_option(ENABLE_UNIT_TESTING "Enable unit testing")
@@ -429,10 +428,6 @@ if(ENABLE_PROOFS)
add_definitions(-DCVC4_PROOF)
endif()
-if(ENABLE_REPLAY)
- add_definitions(-DCVC4_REPLAY)
-endif()
-
if(ENABLE_TRACING)
add_definitions(-DCVC4_TRACING)
endif()
@@ -608,7 +603,6 @@ message("")
print_config("Dumping :" ENABLE_DUMPING)
print_config("Muzzle :" ENABLE_MUZZLE)
print_config("Proofs :" ENABLE_PROOFS)
-print_config("Replay :" ENABLE_REPLAY)
print_config("Statistics :" ENABLE_STATISTICS)
print_config("Tracing :" ENABLE_TRACING)
message("")
diff --git a/README.md b/README.md
index b22882d57..e2318ec55 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
[![License: BSD](
https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](
https://opensource.org/licenses/BSD-3-Clause)
-[![Build Status](
- https://travis-ci.org/CVC4/CVC4.svg?branch=master)](
- https://travis-ci.org/CVC4/CVC4)
+![CI](https://github.com/CVC4/CVC4/workflows/CI/badge.svg)
+[![Coverage](
+ https://img.shields.io/endpoint?url=https://cvc4.cs.stanford.edu/downloads/builds/coverage/nightly-coverage.json)](
+ https://cvc4.cs.stanford.edu/downloads/builds/coverage)
CVC4
===============================================================================
diff --git a/cmake/ConfigCompetition.cmake b/cmake/ConfigCompetition.cmake
index 6bd846d0c..e18d2b2f1 100644
--- a/cmake/ConfigCompetition.cmake
+++ b/cmake/ConfigCompetition.cmake
@@ -8,8 +8,6 @@ set(OPTIMIZATION_LEVEL 9)
cvc4_set_option(ENABLE_DEBUG_SYMBOLS OFF)
# enable_statistics=no
cvc4_set_option(ENABLE_STATISTICS OFF)
-# enable_replay=no
-cvc4_set_option(ENABLE_REPLAY OFF)
# enable_assertions=no
cvc4_set_option(ENABLE_ASSERTIONS OFF)
# enable_proof=no
diff --git a/cmake/ConfigDebug.cmake b/cmake/ConfigDebug.cmake
index 31b142ffc..1ee78a602 100644
--- a/cmake/ConfigDebug.cmake
+++ b/cmake/ConfigDebug.cmake
@@ -7,8 +7,6 @@ add_c_cxx_flag("-Og")
cvc4_set_option(ENABLE_DEBUG_SYMBOLS ON)
# enable_statistics=yes
cvc4_set_option(ENABLE_STATISTICS ON)
-# enable_replay=yes
-cvc4_set_option(ENABLE_REPLAY ON)
# enable_assertions=yes
cvc4_set_option(ENABLE_ASSERTIONS ON)
# enable_proof=yes
diff --git a/cmake/ConfigProduction.cmake b/cmake/ConfigProduction.cmake
index 49e338abf..503f5d58f 100644
--- a/cmake/ConfigProduction.cmake
+++ b/cmake/ConfigProduction.cmake
@@ -4,8 +4,6 @@ set(OPTIMIZATION_LEVEL 3)
cvc4_set_option(ENABLE_DEBUG_SYMBOLS OFF)
# enable_statistics=yes
cvc4_set_option(ENABLE_STATISTICS ON)
-# enable_replay=no
-cvc4_set_option(ENABLE_REPLAY OFF)
# enable_assertions=no
cvc4_set_option(ENABLE_ASSERTIONS OFF)
# enable_proof=yes
diff --git a/cmake/ConfigTesting.cmake b/cmake/ConfigTesting.cmake
index 40366495d..cdc9e3af8 100644
--- a/cmake/ConfigTesting.cmake
+++ b/cmake/ConfigTesting.cmake
@@ -4,8 +4,6 @@ set(OPTIMIZATION_LEVEL 2)
cvc4_set_option(ENABLE_DEBUG_SYMBOLS ON)
# enable_statistics=yes
cvc4_set_option(ENABLE_STATISTICS ON)
-# enable_replay=yes
-cvc4_set_option(ENABLE_REPLAY ON)
# enable_assertions=yes
cvc4_set_option(ENABLE_ASSERTIONS ON)
# enable_proof=yes
diff --git a/configure.sh b/configure.sh
index ae9b275aa..070e2c230 100755
--- a/configure.sh
+++ b/configure.sh
@@ -1,6 +1,8 @@
-#!/bin/sh
+#!/bin/bash
#--------------------------------------------------------------------------#
+set -e -o pipefail
+
usage () {
cat <<EOF
Usage: $0 [<build type>] [<option> ...]
@@ -34,7 +36,6 @@ The following flags enable optional features (disable with --no-<option name>).
--valgrind Valgrind instrumentation
--debug-context-mm use the debug context memory manager
--statistics include statistics
- --replay turn on the replay feature
--assertions turn on assertions
--tracing include tracing code
--dumping include dumping code
@@ -130,7 +131,6 @@ lfsc=default
muzzle=default
optimized=default
proofs=default
-replay=default
shared=default
static_binary=default
statistics=default
@@ -248,9 +248,6 @@ do
--proofs) proofs=ON;;
--no-proofs) proofs=OFF;;
- --replay) replay=ON;;
- --no-replay) replay=OFF;;
-
--static) shared=OFF; static_binary=ON;;
--no-static) shared=ON;;
@@ -387,8 +384,6 @@ cmake_opts=""
&& cmake_opts="$cmake_opts -DENABLE_OPTIMIZED=$optimized"
[ $proofs != default ] \
&& cmake_opts="$cmake_opts -DENABLE_PROOFS=$proofs"
-[ $replay != default ] \
- && cmake_opts="$cmake_opts -DENABLE_REPLAY=$replay"
[ $shared != default ] \
&& cmake_opts="$cmake_opts -DENABLE_SHARED=$shared"
[ $static_binary != default ] \
@@ -465,7 +460,7 @@ root_dir=$(pwd)
[ $win64 = ON ] && [ -e "$build_dir" ] && rm -r "$build_dir"
mkdir -p "$build_dir"
-cd "$build_dir" || exit 1
+cd "$build_dir"
[ -e CMakeCache.txt ] && rm CMakeCache.txt
build_dir_escaped=$(echo "$build_dir" | sed 's/\//\\\//g')
diff --git a/contrib/get-antlr-3.4 b/contrib/get-antlr-3.4
index 9ab0695b7..bc75e8339 100755
--- a/contrib/get-antlr-3.4
+++ b/contrib/get-antlr-3.4
@@ -26,15 +26,15 @@ if [ -z "${MACHINE_TYPE}" ]; then
MACHINE_TYPE=$(${CONFIG_GUESS_SCRIPT} | sed 's,-.*,,')
fi
-mkdir -p "$ANTLR_HOME_DIR/share/java"
+mkdir -p "$INSTALL_DIR/share/java"
webget \
"https://www.antlr3.org/download/antlr-3.4-complete.jar" \
- "$ANTLR_HOME_DIR/share/java/antlr-3.4-complete.jar"
+ "$INSTALL_DIR/share/java/antlr-3.4-complete.jar"
mkdir -p "$ANTLR_HOME_DIR/bin"
tee "$ANTLR_HOME_DIR/bin/antlr3" <<EOF
#!/usr/bin/env bash
-export CLASSPATH=$ANTLR_HOME_DIR/share/java/antlr-3.4-complete.jar:\$CLASSPATH
+export CLASSPATH=$INSTALL_DIR/share/java/antlr-3.4-complete.jar:\$CLASSPATH
exec java org.antlr.Tool "\$@"
EOF
chmod a+x "$ANTLR_HOME_DIR/bin/antlr3"
diff --git a/examples/SimpleVC.java b/examples/SimpleVC.java
index e77a5e99f..798dc08af 100644
--- a/examples/SimpleVC.java
+++ b/examples/SimpleVC.java
@@ -55,8 +55,9 @@ public class SimpleVC {
new Expr(em.mkExpr(Kind.AND, x_positive, y_positive)).
impExpr(new Expr(twox_plus_y_geq_3));
- System.out.println("Checking validity of formula " + formula + " with CVC4.");
- System.out.println("CVC4 should report VALID.");
- System.out.println("Result from CVC4 is: " + smt.query(formula));
+ System.out.println(
+ "Checking entailment of formula " + formula + " with CVC4.");
+ System.out.println("CVC4 should report ENTAILED.");
+ System.out.println("Result from CVC4 is: " + smt.checkEntailed(formula));
}
}
diff --git a/examples/SimpleVC.ml b/examples/SimpleVC.ml
index c89341dc8..d9d78586b 100644
--- a/examples/SimpleVC.ml
+++ b/examples/SimpleVC.ml
@@ -79,13 +79,13 @@ let formula = em->mkExpr(implies, lhs, twox_plus_y_geq_3)
let bformula = new_Expr(formula) in
-print_string "Checking validity of formula " ;
+print_string "Checking entailment of formula " ;
print_string (get_string (formula->toString ())) ;
print_string " with CVC4." ;
print_newline () ;
-print_string "CVC4 should report VALID." ;
+print_string "CVC4 should report ENTAILED." ;
print_newline () ;
print_string "Result from CVC4 is: " ;
-print_string (get_string (smt->query(bformula)->toString ())) ;
+print_string (get_string (smt->checkEntailed(bformula)->toString ())) ;
print_newline ()
;;
diff --git a/examples/SimpleVC.php b/examples/SimpleVC.php
index 329446703..031c0a1c5 100755
--- a/examples/SimpleVC.php
+++ b/examples/SimpleVC.php
@@ -50,7 +50,7 @@ my $twox_plus_y_geq_3 = $em->mkExpr($CVC4::GEQ, $twox_plus_y, $three);
my $formula = new CVC4::Expr($em->mkExpr($CVC4::AND, $x_positive, $y_positive))->impExpr(new CVC4::Expr($twox_plus_y_geq_3));
-print "Checking validity of formula " . $formula->toString() . " with CVC4.\n";
-print "CVC4 should report VALID.\n";
-print "Result from CVC4 is: " . $smt->query($formula)->toString() . "\n";
+print "Checking entailment of formula " . $formula->toString() . " with CVC4.\n";
+print "CVC4 should report ENTAILED.\n";
+print "Result from CVC4 is: " . $smt->checkEntailed($formula)->toString() . "\n";
diff --git a/examples/SimpleVC.pl b/examples/SimpleVC.pl
index 998c28bb0..20ad6c737 100755
--- a/examples/SimpleVC.pl
+++ b/examples/SimpleVC.pl
@@ -50,7 +50,7 @@ my $twox_plus_y_geq_3 = $em->mkExpr($CVC4::GEQ, $twox_plus_y, $three);
my $formula = new CVC4::Expr($em->mkExpr($CVC4::AND, $x_positive, $y_positive))->impExpr(new CVC4::Expr($twox_plus_y_geq_3));
-print "Checking validity of formula " . $formula->toString() . " with CVC4.\n";
-print "CVC4 should report VALID.\n";
-print "Result from CVC4 is: " . $smt->query($formula)->toString() . "\n";
+print "Checking entailment of formula " . $formula->toString() . " with CVC4.\n";
+print "CVC4 should report ENTAILED.\n";
+print "Result from CVC4 is: " . $smt->checkEntailed($formula)->toString() . "\n";
diff --git a/examples/SimpleVC.py b/examples/SimpleVC.py
index 4c21d35c0..5550974c9 100755
--- a/examples/SimpleVC.py
+++ b/examples/SimpleVC.py
@@ -53,9 +53,9 @@ def main():
formula = Expr(em.mkExpr(CVC4.AND, x_positive, y_positive)).impExpr(Expr(twox_plus_y_geq_3))
- print("Checking validity of formula " + formula.toString() + " with CVC4.")
- print("CVC4 should report VALID.")
- print("Result from CVC4 is: " + smt.query(formula).toString())
+ print("Checking entailment of formula " + formula.toString() + " with CVC4.")
+ print("CVC4 should report ENTAILED .")
+ print("Result from CVC4 is: " + smt.checkEntailed(formula).toString())
return 0
diff --git a/examples/SimpleVC.rb b/examples/SimpleVC.rb
index 0d19ef49f..4f289d34f 100755
--- a/examples/SimpleVC.rb
+++ b/examples/SimpleVC.rb
@@ -49,9 +49,9 @@ twox_plus_y_geq_3 = em.mkExpr(GEQ, twox_plus_y, three)
formula = Expr.new(em.mkExpr(AND, x_positive, y_positive)).impExpr(Expr.new(twox_plus_y_geq_3))
-puts "Checking validity of formula " + formula.toString + " with CVC4."
-puts "CVC4 should report VALID."
-puts "Result from CVC4 is: " + smt.query(formula).toString
+puts "Checking entailment of formula " + formula.toString + " with CVC4."
+puts "CVC4 should report ENTAILED."
+puts "Result from CVC4 is: " + smt.checkEntailed(formula).toString
exit
diff --git a/examples/SimpleVC.tcl b/examples/SimpleVC.tcl
index ed0decb26..4e1c76c5a 100755
--- a/examples/SimpleVC.tcl
+++ b/examples/SimpleVC.tcl
@@ -48,7 +48,7 @@ set twox_plus_y_geq_3 [ExprManager_mkExpr em $GEQ $twox_plus_y $three]
set formula [Expr_impExpr [Expr _1 [ExprManager_mkExpr em $AND $x_positive $y_positive]] [Expr _2 $twox_plus_y_geq_3]]
-puts "Checking validity of formula [Expr_toString $formula] with CVC4."
-puts "CVC4 should report VALID."
-puts "Result from CVC4 is: [Result_toString [SmtEngine_query smt $formula]]"
+puts "Checking entailment of formula [Expr_toString $formula] with CVC4."
+puts "CVC4 should report ENTAILED."
+puts "Result from CVC4 is: [Result_toString [SmtEngine_checkEntailed smt $formula]]"
diff --git a/examples/api/bitvectors-new.cpp b/examples/api/bitvectors-new.cpp
index 4578da733..ebb8ee7ee 100644
--- a/examples/api/bitvectors-new.cpp
+++ b/examples/api/bitvectors-new.cpp
@@ -87,9 +87,9 @@ int main()
slv.assertFormula(assignment1);
Term new_x_eq_new_x_ = slv.mkTerm(EQUAL, new_x, new_x_);
- cout << " Check validity assuming: " << new_x_eq_new_x_ << endl;
- cout << " Expect valid. " << endl;
- cout << " CVC4: " << slv.checkValidAssuming(new_x_eq_new_x_) << endl;
+ cout << " Check entailment assuming: " << new_x_eq_new_x_ << endl;
+ cout << " Expect ENTAILED. " << endl;
+ cout << " CVC4: " << slv.checkEntailed(new_x_eq_new_x_) << endl;
cout << " Popping context. " << endl;
slv.pop();
@@ -103,15 +103,15 @@ int main()
cout << "Asserting " << assignment2 << " to CVC4 " << endl;
slv.assertFormula(assignment2);
- cout << " Check validity assuming: " << new_x_eq_new_x_ << endl;
- cout << " Expect valid. " << endl;
- cout << " CVC4: " << slv.checkValidAssuming(new_x_eq_new_x_) << endl;
+ cout << " Check entailment assuming: " << new_x_eq_new_x_ << endl;
+ cout << " Expect ENTAILED. " << endl;
+ cout << " CVC4: " << slv.checkEntailed(new_x_eq_new_x_) << endl;
Term x_neq_x = slv.mkTerm(EQUAL, x, x).notTerm();
std::vector<Term> v{new_x_eq_new_x_, x_neq_x};
- cout << " Check Validity Assuming: " << v << endl;
- cout << " Expect invalid. " << endl;
- cout << " CVC4: " << slv.checkValidAssuming(v) << endl;
+ cout << " Check entailment assuming: " << v << endl;
+ cout << " Expect NOT_ENTAILED. " << endl;
+ cout << " CVC4: " << slv.checkEntailed(v) << endl;
// Assert that a is odd
Op extract_op = slv.mkOp(BITVECTOR_EXTRACT, 0, 0);
diff --git a/examples/api/bitvectors.cpp b/examples/api/bitvectors.cpp
index 259eb48ff..494a45abc 100644
--- a/examples/api/bitvectors.cpp
+++ b/examples/api/bitvectors.cpp
@@ -87,8 +87,8 @@ int main() {
Expr new_x_eq_new_x_ = em.mkExpr(kind::EQUAL, new_x, new_x_);
cout << " Querying: " << new_x_eq_new_x_ << endl;
- cout << " Expect valid. " << endl;
- cout << " CVC4: " << smt.query(new_x_eq_new_x_) << endl;
+ cout << " Expect entailed. " << endl;
+ cout << " CVC4: " << smt.checkEntailed(new_x_eq_new_x_) << endl;
cout << " Popping context. " << endl;
smt.pop();
@@ -103,14 +103,14 @@ int main() {
smt.assertFormula(assignment2);
cout << " Querying: " << new_x_eq_new_x_ << endl;
- cout << " Expect valid. " << endl;
- cout << " CVC4: " << smt.query(new_x_eq_new_x_) << endl;
+ cout << " Expect ENTAILED. " << endl;
+ cout << " CVC4: " << smt.checkEntailed(new_x_eq_new_x_) << endl;
Expr x_neq_x = em.mkExpr(kind::EQUAL, x, x).notExpr();
std::vector<Expr> v{new_x_eq_new_x_, x_neq_x};
cout << " Querying: " << v << endl;
- cout << " Expect invalid. " << endl;
- cout << " CVC4: " << smt.query(v) << endl;
+ cout << " Expect NOT_ENTAILED. " << endl;
+ cout << " CVC4: " << smt.checkEntailed(v) << endl;
// Assert that a is odd
Expr extract_op = em.mkConst(BitVectorExtract(0, 0));
diff --git a/examples/api/combination-new.cpp b/examples/api/combination-new.cpp
index 5284a0119..546d9ee9c 100644
--- a/examples/api/combination-new.cpp
+++ b/examples/api/combination-new.cpp
@@ -82,9 +82,10 @@ int main()
cout << "Given the following assertions:" << endl
<< assertions << endl << endl;
- cout << "Prove x /= y is valid. " << endl
- << "CVC4: " << slv.checkValidAssuming(slv.mkTerm(DISTINCT, x, y))
- << "." << endl << endl;
+ cout << "Prove x /= y is entailed. " << endl
+ << "CVC4: " << slv.checkEntailed(slv.mkTerm(DISTINCT, x, y)) << "."
+ << endl
+ << endl;
cout << "Call checkSat to show that the assertions are satisfiable. "
<< endl
diff --git a/examples/api/combination.cpp b/examples/api/combination.cpp
index 646e6b17a..2e972a543 100644
--- a/examples/api/combination.cpp
+++ b/examples/api/combination.cpp
@@ -86,8 +86,8 @@ int main() {
cout << "Given the following assumptions:" << endl
<< assumptions << endl
- << "Prove x /= y is valid. "
- << "CVC4 says: " << smt.query(em.mkExpr(kind::DISTINCT, x, y))
+ << "Prove x /= y is entailed. "
+ << "CVC4 says: " << smt.checkEntailed(em.mkExpr(kind::DISTINCT, x, y))
<< "." << endl;
cout << "Now we call checksat on a trivial query to show that" << endl
diff --git a/examples/api/extract-new.cpp b/examples/api/extract-new.cpp
index 0f0f8243a..705cdd90f 100644
--- a/examples/api/extract-new.cpp
+++ b/examples/api/extract-new.cpp
@@ -47,9 +47,9 @@ int main()
slv.assertFormula(eq);
Term eq2 = slv.mkTerm(EQUAL, x_31_31, x_0_0);
- cout << " Check validity assuming: " << eq2 << endl;
- cout << " Expect valid. " << endl;
- cout << " CVC4: " << slv.checkValidAssuming(eq2) << endl;
+ cout << " Check entailment assuming: " << eq2 << endl;
+ cout << " Expect ENTAILED. " << endl;
+ cout << " CVC4: " << slv.checkEntailed(eq2) << endl;
return 0;
}
diff --git a/examples/api/extract.cpp b/examples/api/extract.cpp
index a008ec718..e2558df28 100644
--- a/examples/api/extract.cpp
+++ b/examples/api/extract.cpp
@@ -48,8 +48,8 @@ int main() {
Expr eq2 = em.mkExpr(kind::EQUAL, x_31_31, x_0_0);
cout << " Querying: " << eq2 << endl;
- cout << " Expect valid. " << endl;
- cout << " CVC4: " << smt.query(eq2) << endl;
+ cout << " Expect entailed. " << endl;
+ cout << " CVC4: " << smt.checkEntailed(eq2) << endl;
return 0;
}
diff --git a/examples/api/helloworld-new.cpp b/examples/api/helloworld-new.cpp
index ab869f03c..f442c1412 100644
--- a/examples/api/helloworld-new.cpp
+++ b/examples/api/helloworld-new.cpp
@@ -24,7 +24,7 @@ int main()
{
Solver slv;
Term helloworld = slv.mkVar(slv.getBooleanSort(), "Hello World!");
- std::cout << helloworld << " is " << slv.checkValidAssuming(helloworld)
+ std::cout << helloworld << " is " << slv.checkEntailed(helloworld)
<< std::endl;
return 0;
}
diff --git a/examples/api/helloworld.cpp b/examples/api/helloworld.cpp
index befeaa7bd..49a334504 100644
--- a/examples/api/helloworld.cpp
+++ b/examples/api/helloworld.cpp
@@ -23,6 +23,7 @@ int main() {
ExprManager em;
Expr helloworld = em.mkVar("Hello World!", em.booleanType());
SmtEngine smt(&em);
- std::cout << helloworld << " is " << smt.query(helloworld) << std::endl;
+ std::cout << helloworld << " is " << smt.checkEntailed(helloworld)
+ << std::endl;
return 0;
}
diff --git a/examples/api/java/BitVectors.java b/examples/api/java/BitVectors.java
index 17111b63a..bb2245a6f 100644
--- a/examples/api/java/BitVectors.java
+++ b/examples/api/java/BitVectors.java
@@ -86,8 +86,8 @@ public class BitVectors {
Expr new_x_eq_new_x_ = em.mkExpr(Kind.EQUAL, new_x, new_x_);
System.out.println(" Querying: " + new_x_eq_new_x_);
- System.out.println(" Expect valid. ");
- System.out.println(" CVC4: " + smt.query(new_x_eq_new_x_));
+ System.out.println(" Expect entailed. ");
+ System.out.println(" CVC4: " + smt.checkEntailed(new_x_eq_new_x_));
System.out.println(" Popping context. ");
smt.pop();
@@ -102,7 +102,7 @@ public class BitVectors {
smt.assertFormula(assignment2);
System.out.println(" Querying: " + new_x_eq_new_x_);
- System.out.println(" Expect valid. ");
- System.out.println(" CVC4: " + smt.query(new_x_eq_new_x_));
+ System.out.println(" Expect entailed. ");
+ System.out.println(" CVC4: " + smt.checkEntailed(new_x_eq_new_x_));
}
}
diff --git a/examples/api/java/Combination.java b/examples/api/java/Combination.java
index 0c9ca84d6..53b1fa92d 100644
--- a/examples/api/java/Combination.java
+++ b/examples/api/java/Combination.java
@@ -83,10 +83,9 @@ public class Combination {
System.out.println("Given the following assumptions:");
System.out.println(assumptions);
- System.out.println("Prove x /= y is valid. " +
- "CVC4 says: " + smt.query(em.mkExpr(Kind.DISTINCT, x, y)) +
- ".");
-
+ System.out.println("Prove x /= y is entailed. "
+ + "CVC4 says: " + smt.checkEntailed(em.mkExpr(Kind.DISTINCT, x, y))
+ + ".");
System.out.println("Now we call checksat on a trivial query to show that");
System.out.println("the assumptions are satisfiable: " +
diff --git a/examples/api/java/HelloWorld.java b/examples/api/java/HelloWorld.java
index 393ce40f0..a08f3d452 100644
--- a/examples/api/java/HelloWorld.java
+++ b/examples/api/java/HelloWorld.java
@@ -30,6 +30,6 @@ public class HelloWorld {
Expr helloworld = em.mkVar("Hello World!", em.booleanType());
SmtEngine smt = new SmtEngine(em);
- System.out.println(helloworld + " is " + smt.query(helloworld));
+ System.out.println(helloworld + " is " + smt.checkEntailed(helloworld));
}
}
diff --git a/examples/api/java/LinearArith.java b/examples/api/java/LinearArith.java
index 2ddf92584..e060263b4 100644
--- a/examples/api/java/LinearArith.java
+++ b/examples/api/java/LinearArith.java
@@ -61,8 +61,9 @@ public class LinearArith {
smt.push();
Expr diff_leq_two_thirds = em.mkExpr(Kind.LEQ, diff, two_thirds);
System.out.println("Prove that " + diff_leq_two_thirds + " with CVC4.");
- System.out.println("CVC4 should report VALID.");
- System.out.println("Result from CVC4 is: " + smt.query(diff_leq_two_thirds));
+ System.out.println("CVC4 should report ENTAILED.");
+ System.out.println(
+ "Result from CVC4 is: " + smt.checkEntailed(diff_leq_two_thirds));
smt.pop();
System.out.println();
diff --git a/examples/api/linear_arith-new.cpp b/examples/api/linear_arith-new.cpp
index a4ff9a2cc..887c35d24 100644
--- a/examples/api/linear_arith-new.cpp
+++ b/examples/api/linear_arith-new.cpp
@@ -62,9 +62,9 @@ int main()
slv.push();
Term diff_leq_two_thirds = slv.mkTerm(LEQ, diff, two_thirds);
cout << "Prove that " << diff_leq_two_thirds << " with CVC4." << endl;
- cout << "CVC4 should report VALID." << endl;
- cout << "Result from CVC4 is: "
- << slv.checkValidAssuming(diff_leq_two_thirds) << endl;
+ cout << "CVC4 should report ENTAILED." << endl;
+ cout << "Result from CVC4 is: " << slv.checkEntailed(diff_leq_two_thirds)
+ << endl;
slv.pop();
cout << endl;
diff --git a/examples/api/linear_arith.cpp b/examples/api/linear_arith.cpp
index f1c8b861c..9e605f85c 100644
--- a/examples/api/linear_arith.cpp
+++ b/examples/api/linear_arith.cpp
@@ -62,8 +62,9 @@ int main() {
smt.push();
Expr diff_leq_two_thirds = em.mkExpr(kind::LEQ, diff, two_thirds);
cout << "Prove that " << diff_leq_two_thirds << " with CVC4." << endl;
- cout << "CVC4 should report VALID." << endl;
- cout << "Result from CVC4 is: " << smt.query(diff_leq_two_thirds) << endl;
+ cout << "CVC4 should report ENTAILED." << endl;
+ cout << "Result from CVC4 is: " << smt.checkEntailed(diff_leq_two_thirds)
+ << endl;
smt.pop();
cout << endl;
diff --git a/examples/api/python/bitvectors.py b/examples/api/python/bitvectors.py
index 773974cc7..8e4e1b682 100755
--- a/examples/api/python/bitvectors.py
+++ b/examples/api/python/bitvectors.py
@@ -4,7 +4,7 @@
#! \file bitvectors.py
## \verbatim
## Top contributors (to current version):
- ## Makai Mann
+ ## Makai Mann, Aina Niemetz
## This file is part of the CVC4 project.
## Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
## in the top-level source directory) and their institutional affiliations.
@@ -82,9 +82,9 @@ if __name__ == "__main__":
slv.assertFormula(assignment1)
new_x_eq_new_x_ = slv.mkTerm(kinds.Equal, new_x, new_x_)
- print("Checking validity assuming:", new_x_eq_new_x_)
- print("Expect valid.")
- print("CVC4:", slv.checkValidAssuming(new_x_eq_new_x_))
+ print("Checking entailment assuming:", new_x_eq_new_x_)
+ print("Expect ENTAILED.")
+ print("CVC4:", slv.checkEntailment(new_x_eq_new_x_))
print("Popping context.")
slv.pop()
@@ -98,16 +98,16 @@ if __name__ == "__main__":
print("Asserting {} to CVC4".format(assignment2))
slv.assertFormula(assignment2)
- print("Checking validity assuming:", new_x_eq_new_x_)
- print("Expect valid.")
- print("CVC4:", slv.checkValidAssuming(new_x_eq_new_x_))
+ print("Checking entailment assuming:", new_x_eq_new_x_)
+ print("Expect ENTAILED.")
+ print("CVC4:", slv.checkEntailed(new_x_eq_new_x_))
x_neq_x = slv.mkTerm(kinds.Equal, x, x).notTerm()
v = [new_x_eq_new_x_, x_neq_x]
- print("Check Validity Assuming: ", v)
- print("Expect invalid.")
- print("CVC4:", slv.checkValidAssuming(v))
+ print("Check entailment assuming: ", v)
+ print("Expect NOT_ENTAILED.")
+ print("CVC4:", slv.checkEntailed(v))
# Assert that a is odd
extract_op = slv.mkOp(kinds.BVExtract, 0, 0)
diff --git a/examples/api/python/combination.py b/examples/api/python/combination.py
index 1b488d7d5..7a8055bdf 100755
--- a/examples/api/python/combination.py
+++ b/examples/api/python/combination.py
@@ -4,7 +4,7 @@
#! \file combination.py
## \verbatim
## Top contributors (to current version):
- ## Makai Mann
+ ## Makai Mann, Aina Niemetz
## This file is part of the CVC4 project.
## Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
## in the top-level source directory) and their institutional affiliations.
@@ -69,8 +69,8 @@ if __name__ == "__main__":
slv.assertFormula(assertions)
print("Given the following assertions:", assertions, "\n")
- print("Prove x /= y is valid.\nCVC4: ",
- slv.checkValidAssuming(slv.mkTerm(kinds.Distinct, x, y)), "\n")
+ print("Prove x /= y is entailed.\nCVC4: ",
+ slv.checkEntailed(slv.mkTerm(kinds.Distinct, x, y)), "\n")
print("Call checkSat to show that the assertions are satisfiable")
print("CVC4:", slv.checkSat(), "\n")
diff --git a/examples/api/python/extract.py b/examples/api/python/extract.py
index 1bfdf652a..2b8714739 100755
--- a/examples/api/python/extract.py
+++ b/examples/api/python/extract.py
@@ -4,7 +4,7 @@
#! \file extract.py
## \verbatim
## Top contributors (to current version):
- ## Makai Mann
+ ## Makai Mann, Aina Niemetz
## This file is part of the CVC4 project.
## Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
## in the top-level source directory) and their institutional affiliations.
@@ -46,6 +46,6 @@ if __name__ == "__main__":
slv.assertFormula(eq)
eq2 = slv.mkTerm(Equal, x_31_31, x_0_0)
- print("Check validity assuming:", eq2)
- print("Expect valid")
- print("CVC4:", slv.checkValidAssuming(eq2))
+ print("Check entailment assuming:", eq2)
+ print("Expect ENTAILED")
+ print("CVC4:", slv.checkEntailed(eq2))
diff --git a/examples/api/python/helloworld.py b/examples/api/python/helloworld.py
index 472cf945b..5607d7f83 100755
--- a/examples/api/python/helloworld.py
+++ b/examples/api/python/helloworld.py
@@ -4,7 +4,7 @@
#! \file helloworld.py
## \verbatim
## Top contributors (to current version):
-## Makai Mann
+## Makai Mann, Aina Niemetz
## This file is part of the CVC4 project.
## Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
## in the top-level source directory) and their institutional affiliations.
@@ -18,4 +18,4 @@ from pycvc4 import kinds
if __name__ == "__main__":
slv = pycvc4.Solver()
helloworld = slv.mkConst(slv.getBooleanSort(), "Hello World!")
- print(helloworld, "is", slv.checkValidAssuming(helloworld))
+ print(helloworld, "is", slv.checkEntailed(helloworld))
diff --git a/examples/api/python/linear_arith.py b/examples/api/python/linear_arith.py
index 6ae6427b1..bab9680b3 100755
--- a/examples/api/python/linear_arith.py
+++ b/examples/api/python/linear_arith.py
@@ -4,7 +4,7 @@
#! \file linear_arith.py
## \verbatim
## Top contributors (to current version):
-## Makai Mann
+## Makai Mann, Aina Niemetz
## This file is part of the CVC4 project.
## Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
## in the top-level source directory) and their institutional affiliations.
@@ -54,9 +54,9 @@ if __name__ == "__main__":
slv.push()
diff_leq_two_thirds = slv.mkTerm(kinds.Leq, diff, two_thirds)
print("Prove that", diff_leq_two_thirds, "with CVC4")
- print("CVC4 should report VALID")
+ print("CVC4 should report ENTAILED")
print("Result from CVC4 is:",
- slv.checkValidAssuming(diff_leq_two_thirds))
+ slv.checkEntailed(diff_leq_two_thirds))
slv.pop()
print()
diff --git a/examples/api/python/sets.py b/examples/api/python/sets.py
index 584880b2b..b69c56b56 100755
--- a/examples/api/python/sets.py
+++ b/examples/api/python/sets.py
@@ -4,7 +4,7 @@
#! \file sets.py
## \verbatim
## Top contributors (to current version):
-## Makai Mann
+## Makai Mann, Aina Niemetz
## This file is part of the CVC4 project.
## Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
## in the top-level source directory) and their institutional affiliations.
@@ -48,7 +48,7 @@ if __name__ == "__main__":
theorem = slv.mkTerm(kinds.Equal, lhs, rhs)
print("CVC4 reports: {} is {}".format(theorem,
- slv.checkValidAssuming(theorem)))
+ slv.checkEntailed(theorem)))
# Verify emptset is a subset of any set
@@ -58,7 +58,7 @@ if __name__ == "__main__":
theorem = slv.mkTerm(kinds.Subset, emptyset, A)
print("CVC4 reports: {} is {}".format(theorem,
- slv.checkValidAssuming(theorem)))
+ slv.checkEntailed(theorem)))
# Find me an element in 1, 2 intersection 2, 3, if there is one.
diff --git a/examples/api/sets-new.cpp b/examples/api/sets-new.cpp
index 2ca3db9d2..21ef925df 100644
--- a/examples/api/sets-new.cpp
+++ b/examples/api/sets-new.cpp
@@ -52,8 +52,8 @@ int main()
Term theorem = slv.mkTerm(EQUAL, lhs, rhs);
- cout << "CVC4 reports: " << theorem << " is "
- << slv.checkValidAssuming(theorem) << "." << endl;
+ cout << "CVC4 reports: " << theorem << " is " << slv.checkEntailed(theorem)
+ << "." << endl;
}
// Verify emptset is a subset of any set
@@ -63,8 +63,8 @@ int main()
Term theorem = slv.mkTerm(SUBSET, emptyset, A);
- cout << "CVC4 reports: " << theorem << " is "
- << slv.checkValidAssuming(theorem) << "." << endl;
+ cout << "CVC4 reports: " << theorem << " is " << slv.checkEntailed(theorem)
+ << "." << endl;
}
// Find me an element in {1, 2} intersection {2, 3}, if there is one.
diff --git a/examples/api/sets.cpp b/examples/api/sets.cpp
index 9fb342431..eb6a5a350 100644
--- a/examples/api/sets.cpp
+++ b/examples/api/sets.cpp
@@ -55,7 +55,8 @@ int main() {
Expr theorem = em.mkExpr(kind::EQUAL, lhs, rhs);
- cout << "CVC4 reports: " << theorem << " is " << smt.query(theorem) << "." << endl;
+ cout << "CVC4 reports: " << theorem << " is " << smt.checkEntailed(theorem)
+ << "." << endl;
}
// Verify emptset is a subset of any set
@@ -65,7 +66,8 @@ int main() {
Expr theorem = em.mkExpr(kind::SUBSET, emptyset, A);
- cout << "CVC4 reports: " << theorem << " is " << smt.query(theorem) << "." << endl;
+ cout << "CVC4 reports: " << theorem << " is " << smt.checkEntailed(theorem)
+ << "." << endl;
}
// Find me an element in {1, 2} intersection {2, 3}, if there is one.
diff --git a/examples/simple_vc_cxx.cpp b/examples/simple_vc_cxx.cpp
index 25a05a1a7..cfd14b089 100644
--- a/examples/simple_vc_cxx.cpp
+++ b/examples/simple_vc_cxx.cpp
@@ -50,9 +50,9 @@ int main() {
em.mkExpr(kind::AND, x_positive, y_positive).
impExpr(twox_plus_y_geq_3);
- cout << "Checking validity of formula " << formula << " with CVC4." << endl;
- cout << "CVC4 should report VALID." << endl;
- cout << "Result from CVC4 is: " << smt.query(formula) << endl;
+ cout << "Checking entailment of formula " << formula << " with CVC4." << endl;
+ cout << "CVC4 should report ENTAILED." << endl;
+ cout << "Result from CVC4 is: " << smt.checkEntailed(formula) << endl;
return 0;
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4520ee421..c1c8c15e0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -236,6 +236,8 @@ libcvc4_add_sources(
smt/model_core_builder.h
smt/model_blocker.cpp
smt/model_blocker.h
+ smt/set_defaults.cpp
+ smt/set_defaults.h
smt/smt_engine.cpp
smt/smt_engine.h
smt/smt_engine_scope.cpp
@@ -291,6 +293,7 @@ libcvc4_add_sources(
theory/arith/linear_equality.h
theory/arith/matrix.cpp
theory/arith/matrix.h
+ theory/arith/nl_lemma_utils.cpp
theory/arith/nl_lemma_utils.h
theory/arith/nl_model.cpp
theory/arith/nl_model.h
@@ -316,6 +319,8 @@ libcvc4_add_sources(
theory/arith/theory_arith_private.h
theory/arith/theory_arith_private_forward.h
theory/arith/theory_arith_type_rules.h
+ theory/arith/transcendental_solver.cpp
+ theory/arith/transcendental_solver.h
theory/arith/type_enumerator.h
theory/arrays/array_info.cpp
theory/arrays/array_info.h
@@ -422,14 +427,6 @@ libcvc4_add_sources(
theory/fp/theory_fp_rewriter.h
theory/fp/theory_fp_type_rules.h
theory/fp/type_enumerator.h
- theory/idl/idl_assertion.cpp
- theory/idl/idl_assertion.h
- theory/idl/idl_assertion_db.cpp
- theory/idl/idl_assertion_db.h
- theory/idl/idl_model.cpp
- theory/idl/idl_model.h
- theory/idl/theory_idl.cpp
- theory/idl/theory_idl.h
theory/interrupted.h
theory/logic_info.cpp
theory/logic_info.h
@@ -679,6 +676,8 @@ libcvc4_add_sources(
theory/strings/regexp_operation.h
theory/strings/regexp_solver.cpp
theory/strings/regexp_solver.h
+ theory/strings/rewrites.cpp
+ theory/strings/rewrites.h
theory/strings/sequences_rewriter.cpp
theory/strings/sequences_rewriter.h
theory/strings/sequences_stats.cpp
@@ -762,8 +761,7 @@ set(KINDS_FILES
${PROJECT_SOURCE_DIR}/src/theory/sep/kinds
${PROJECT_SOURCE_DIR}/src/theory/sets/kinds
${PROJECT_SOURCE_DIR}/src/theory/strings/kinds
- ${PROJECT_SOURCE_DIR}/src/theory/quantifiers/kinds
- ${PROJECT_SOURCE_DIR}/src/theory/idl/kinds)
+ ${PROJECT_SOURCE_DIR}/src/theory/quantifiers/kinds)
#-----------------------------------------------------------------------------#
# Add subdirectories
@@ -898,7 +896,6 @@ install(FILES
expr/datatype.h
expr/emptyset.h
expr/expr_iomanip.h
- expr/expr_stream.h
expr/record.h
expr/symbol_table.h
expr/type.h
@@ -964,6 +961,7 @@ install(FILES
util/result.h
util/sexpr.h
util/statistics.h
+ util/string.h
util/tuple.h
util/unsafe_interrupt_exception.h
${CMAKE_CURRENT_BINARY_DIR}/util/floatingpoint.h
diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp
index f563e83f5..2e6e70d6b 100644
--- a/src/api/cvc4cpp.cpp
+++ b/src/api/cvc4cpp.cpp
@@ -277,6 +277,7 @@ const static std::unordered_map<Kind, CVC4::Kind, KindHashFunction> s_kinds{
{REGEXP_PLUS, CVC4::Kind::REGEXP_PLUS},
{REGEXP_OPT, CVC4::Kind::REGEXP_OPT},
{REGEXP_RANGE, CVC4::Kind::REGEXP_RANGE},
+ {REGEXP_REPEAT, CVC4::Kind::REGEXP_REPEAT},
{REGEXP_LOOP, CVC4::Kind::REGEXP_LOOP},
{REGEXP_EMPTY, CVC4::Kind::REGEXP_EMPTY},
{REGEXP_SIGMA, CVC4::Kind::REGEXP_SIGMA},
@@ -544,6 +545,7 @@ const static std::unordered_map<CVC4::Kind, Kind, CVC4::kind::KindHashFunction>
{CVC4::Kind::REGEXP_PLUS, REGEXP_PLUS},
{CVC4::Kind::REGEXP_OPT, REGEXP_OPT},
{CVC4::Kind::REGEXP_RANGE, REGEXP_RANGE},
+ {CVC4::Kind::REGEXP_REPEAT, REGEXP_REPEAT},
{CVC4::Kind::REGEXP_LOOP, REGEXP_LOOP},
{CVC4::Kind::REGEXP_EMPTY, REGEXP_EMPTY},
{CVC4::Kind::REGEXP_SIGMA, REGEXP_SIGMA},
@@ -766,22 +768,22 @@ bool Result::isSatUnknown(void) const
&& d_result->isSat() == CVC4::Result::SAT_UNKNOWN;
}
-bool Result::isValid(void) const
+bool Result::isEntailed(void) const
{
- return d_result->getType() == CVC4::Result::TYPE_VALIDITY
- && d_result->isValid() == CVC4::Result::VALID;
+ return d_result->getType() == CVC4::Result::TYPE_ENTAILMENT
+ && d_result->isEntailed() == CVC4::Result::ENTAILED;
}
-bool Result::isInvalid(void) const
+bool Result::isNotEntailed(void) const
{
- return d_result->getType() == CVC4::Result::TYPE_VALIDITY
- && d_result->isValid() == CVC4::Result::INVALID;
+ return d_result->getType() == CVC4::Result::TYPE_ENTAILMENT
+ && d_result->isEntailed() == CVC4::Result::NOT_ENTAILED;
}
-bool Result::isValidUnknown(void) const
+bool Result::isEntailmentUnknown(void) const
{
- return d_result->getType() == CVC4::Result::TYPE_VALIDITY
- && d_result->isValid() == CVC4::Result::VALIDITY_UNKNOWN;
+ return d_result->getType() == CVC4::Result::TYPE_ENTAILMENT
+ && d_result->isEntailed() == CVC4::Result::ENTAILMENT_UNKNOWN;
}
bool Result::operator==(const Result& r) const
@@ -2292,7 +2294,7 @@ Term Solver::mkValHelper(T t) const
return res;
}
-Term Solver::mkRealFromStrHelper(std::string s) const
+Term Solver::mkRealFromStrHelper(const std::string& s) const
{
/* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
* throws an std::invalid_argument exception. For consistency, we treat it
@@ -2316,7 +2318,7 @@ Term Solver::mkBVFromIntHelper(uint32_t size, uint64_t val) const
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkBVFromStrHelper(std::string s, uint32_t base) const
+Term Solver::mkBVFromStrHelper(const std::string& s, uint32_t base) const
{
CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string";
CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, s)
@@ -2326,7 +2328,7 @@ Term Solver::mkBVFromStrHelper(std::string s, uint32_t base) const
}
Term Solver::mkBVFromStrHelper(uint32_t size,
- std::string s,
+ const std::string& s,
uint32_t base) const
{
CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string";
@@ -2351,6 +2353,20 @@ Term Solver::mkBVFromStrHelper(uint32_t size,
return mkValHelper<CVC4::BitVector>(CVC4::BitVector(size, val));
}
+Term Solver::mkCharFromStrHelper(const std::string& s) const
+{
+ CVC4_API_CHECK(s.find_first_not_of("0123456789abcdefABCDEF", 0)
+ == std::string::npos
+ && s.size() <= 5 && s.size() > 0)
+ << "Unexpected string for hexidecimal character " << s;
+ uint32_t val = static_cast<uint32_t>(std::stoul(s, 0, 16));
+ CVC4_API_CHECK(val < String::num_codes())
+ << "Not a valid code point for hexidecimal character " << s;
+ std::vector<unsigned> cpts;
+ cpts.push_back(val);
+ return mkValHelper<CVC4::String>(CVC4::String(cpts));
+}
+
Term Solver::mkTermFromKind(Kind kind) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
@@ -2949,6 +2965,21 @@ Term Solver::mkString(const std::vector<unsigned>& s) const
CVC4_API_SOLVER_TRY_CATCH_END;
}
+Term Solver::mkChar(const std::string& s) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ return mkCharFromStrHelper(s);
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+Term Solver::mkChar(const char* s) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_ARG_CHECK_NOT_NULLPTR(s);
+ return mkCharFromStrHelper(std::string(s));
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
Term Solver::mkUniverseSet(Sort sort) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
@@ -3490,6 +3521,11 @@ Op Solver::mkOp(Kind kind, uint32_t arg) const
kind,
*mkValHelper<CVC4::TupleUpdate>(CVC4::TupleUpdate(arg)).d_expr.get());
break;
+ case REGEXP_REPEAT:
+ res = Op(kind,
+ *mkValHelper<CVC4::RegExpRepeat>(CVC4::RegExpRepeat(arg))
+ .d_expr.get());
+ break;
default:
CVC4_API_KIND_CHECK_EXPECTED(false, kind)
<< "operator kind with uint32_t argument";
@@ -3550,6 +3586,11 @@ Op Solver::mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const
CVC4::FloatingPointToFPGeneric(arg1, arg2))
.d_expr.get());
break;
+ case REGEXP_LOOP:
+ res = Op(kind,
+ *mkValHelper<CVC4::RegExpLoop>(CVC4::RegExpLoop(arg1, arg2))
+ .d_expr.get());
+ break;
default:
CVC4_API_KIND_CHECK_EXPECTED(false, kind)
<< "operator kind with two uint32_t arguments";
@@ -3573,7 +3614,7 @@ Term Solver::simplify(const Term& t)
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Result Solver::checkValid(void) const
+Result Solver::checkEntailed(Term term) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
@@ -3581,14 +3622,15 @@ Result Solver::checkValid(void) const
|| CVC4::options::incrementalSolving())
<< "Cannot make multiple queries unless incremental solving is enabled "
"(try --incremental)";
+ CVC4_API_ARG_CHECK_NOT_NULL(term);
- CVC4::Result r = d_smtEngine->query();
+ CVC4::Result r = d_smtEngine->checkEntailed(*term.d_expr);
return Result(r);
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Result Solver::checkValidAssuming(Term assumption) const
+Result Solver::checkEntailed(const std::vector<Term>& terms) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
@@ -3596,29 +3638,13 @@ Result Solver::checkValidAssuming(Term assumption) const
|| CVC4::options::incrementalSolving())
<< "Cannot make multiple queries unless incremental solving is enabled "
"(try --incremental)";
- CVC4_API_ARG_CHECK_NOT_NULL(assumption);
-
- CVC4::Result r = d_smtEngine->query(*assumption.d_expr);
- return Result(r);
-
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-Result Solver::checkValidAssuming(const std::vector<Term>& assumptions) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
- CVC4_API_CHECK(!d_smtEngine->isQueryMade()
- || CVC4::options::incrementalSolving())
- << "Cannot make multiple queries unless incremental solving is enabled "
- "(try --incremental)";
- for (const Term& assumption : assumptions)
+ for (const Term& term : terms)
{
- CVC4_API_ARG_CHECK_NOT_NULL(assumption);
+ CVC4_API_ARG_CHECK_NOT_NULL(term);
}
- std::vector<Expr> eassumptions = termVectorToExprs(assumptions);
- CVC4::Result r = d_smtEngine->query(eassumptions);
+ std::vector<Expr> exprs = termVectorToExprs(terms);
+ CVC4::Result r = d_smtEngine->checkEntailed(exprs);
return Result(r);
CVC4_API_SOLVER_TRY_CATCH_END;
diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h
index 3c99d2480..edff95a2f 100644
--- a/src/api/cvc4cpp.h
+++ b/src/api/cvc4cpp.h
@@ -114,22 +114,21 @@ class CVC4_PUBLIC Result
bool isSatUnknown() const;
/**
- * Return true if corresponding query was a valid checkValid() or
- * checkValidAssuming() query.
+ * Return true if corresponding query was an entailed checkEntailed() query.
*/
- bool isValid() const;
+ bool isEntailed() const;
/**
- * Return true if corresponding query was an invalid checkValid() or
- * checkValidAssuming() query.
+ * Return true if corresponding query was a checkEntailed() query that is
+ * not entailed.
*/
- bool isInvalid() const;
+ bool isNotEntailed() const;
/**
- * Return true if query was a checkValid() or checkValidAssuming() query
- * and CVC4 was not able to determine (in)validity.
+ * Return true if query was a checkEntailed() () query and CVC4 was not able
+ * to determine if it is entailed.
*/
- bool isValidUnknown() const;
+ bool isEntailmentUnknown() const;
/**
* Operator overloading for equality of two results.
@@ -2304,6 +2303,20 @@ class CVC4_PUBLIC Solver
Term mkString(const std::vector<unsigned>& s) const;
/**
+ * Create a character constant from a given string.
+ * @param s the string denoting the code point of the character (in base 16)
+ * @return the character constant
+ */
+ Term mkChar(const std::string& s) const;
+
+ /**
+ * Create a character constant from a given string.
+ * @param s the string denoting the code point of the character (in base 16)
+ * @return the character constant
+ */
+ Term mkChar(const char* s) const;
+
+ /**
* Create a universe set of the given sort.
* @param sort the sort of the set elements
* @return the universe set constant
@@ -2555,24 +2568,19 @@ class CVC4_PUBLIC Solver
Result checkSatAssuming(const std::vector<Term>& assumptions) const;
/**
- * Check validity.
- * @return the result of the validity check.
+ * Check entailment of the given formula w.r.t. the current set of assertions.
+ * @param term the formula to check entailment for
+ * @return the result of the entailment check.
*/
- Result checkValid() const;
+ Result checkEntailed(Term term) const;
/**
- * Check validity assuming the given formula.
- * @param assumption the formula to assume
- * @return the result of the validity check.
- */
- Result checkValidAssuming(Term assumption) const;
-
- /**
- * Check validity assuming the given formulas.
- * @param assumptions the formulas to assume
- * @return the result of the validity check.
+ * Check entailment of the given set of given formulas w.r.t. the current
+ * set of assertions.
+ * @param terms the terms to check entailment for
+ * @return the result of the entailmentcheck.
*/
- Result checkValidAssuming(const std::vector<Term>& assumptions) const;
+ Result checkEntailed(const std::vector<Term>& terms) const;
/**
* Create datatype sort.
@@ -2818,18 +2826,20 @@ class CVC4_PUBLIC Solver
template <typename T>
Term mkValHelper(T t) const;
/* Helper for mkReal functions that take a string as argument. */
- Term mkRealFromStrHelper(std::string s) const;
+ Term mkRealFromStrHelper(const std::string& s) const;
/* Helper for mkBitVector functions that take a string as argument. */
- Term mkBVFromStrHelper(std::string s, uint32_t base) const;
+ Term mkBVFromStrHelper(const std::string& s, uint32_t base) const;
/* Helper for mkBitVector functions that take a string and a size as
* arguments. */
- Term mkBVFromStrHelper(uint32_t size, std::string s, uint32_t base) const;
+ Term mkBVFromStrHelper(uint32_t size, const std::string& s, uint32_t base) const;
/* Helper for mkBitVector functions that take an integer as argument. */
Term mkBVFromIntHelper(uint32_t size, uint64_t val) const;
/* Helper for setLogic. */
void setLogicHelper(const std::string& logic) const;
/* Helper for mkTerm functions that create Term from a Kind */
Term mkTermFromKind(Kind kind) const;
+ /* Helper for mkChar functions that take a string as argument. */
+ Term mkCharFromStrHelper(const std::string& s) const;
/**
* Helper function that ensures that a given term is of sort real (as opposed
diff --git a/src/api/cvc4cppkind.h b/src/api/cvc4cppkind.h
index d399ad616..f8e1fb90c 100644
--- a/src/api/cvc4cppkind.h
+++ b/src/api/cvc4cppkind.h
@@ -2175,15 +2175,37 @@ enum CVC4_PUBLIC Kind : int32_t
*/
REGEXP_RANGE,
/**
- * Regexp loop.
- * Parameters: 2 (3)
- * -[1]: Term of sort RegExp
- * -[2]: Lower bound for the number of repetitions of the first argument
- * -[3]: Upper bound for the number of repetitions of the first argument
+ * Operator for regular expression repeat.
+ * Parameters: 1
+ * -[1]: The number of repetitions
* Create with:
- * mkTerm(Kind kind, Term child1, Term child2)
- * mkTerm(Kind kind, Term child1, Term child2, Term child3)
- * mkTerm(Kind kind, const std::vector<Term>& children)
+ * mkOp(Kind kind, uint32_t param)
+ *
+ * Apply regular expression loop.
+ * Parameters: 2
+ * -[1]: Op of kind REGEXP_REPEAT
+ * -[2]: Term of regular expression sort
+ * Create with:
+ * mkTerm(Op op, Term child)
+ * mkTerm(Op op, const std::vector<Term>& children)
+ */
+ REGEXP_REPEAT,
+ /**
+ * Operator for regular expression loop, from lower bound to upper bound
+ * number of repetitions.
+ * Parameters: 2
+ * -[1]: The lower bound
+ * -[2]: The upper bound
+ * Create with:
+ * mkOp(Kind kind, uint32_t param, uint32_t param)
+ *
+ * Apply regular expression loop.
+ * Parameters: 2
+ * -[1]: Op of kind REGEXP_LOOP
+ * -[2]: Term of regular expression sort
+ * Create with:
+ * mkTerm(Op op, Term child)
+ * mkTerm(Op op, const std::vector<Term>& children)
*/
REGEXP_LOOP,
/**
diff --git a/src/api/python/cvc4.pxd b/src/api/python/cvc4.pxd
index bbff6f58b..d81d0c0bf 100644
--- a/src/api/python/cvc4.pxd
+++ b/src/api/python/cvc4.pxd
@@ -87,9 +87,9 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
bint isSat() except +
bint isUnsat() except +
bint isSatUnknown() except +
- bint isValid() except +
- bint isInvalid() except +
- bint isValidUnknown() except +
+ bint isEntailed() except +
+ bint isNotEntailed() except +
+ bint isEntailmentUnknown() except +
string getUnknownExplanation() except +
string toString() except +
@@ -168,8 +168,7 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
void assertFormula(Term term) except +
Result checkSat() except +
Result checkSatAssuming(const vector[Term]& assumptions) except +
- Result checkValid() except +
- Result checkValidAssuming(const vector[Term]& assumptions) except +
+ Result checkEntailed(const vector[Term]& assumptions) except +
Sort declareDatatype(const string& symbol, const vector[DatatypeConstructorDecl]& ctors)
Term declareFun(const string& symbol, Sort sort) except +
Term declareFun(const string& symbol, const vector[Sort]& sorts, Sort sort) except +
diff --git a/src/api/python/cvc4.pxi b/src/api/python/cvc4.pxi
index 188753122..60bd89cbd 100644
--- a/src/api/python/cvc4.pxi
+++ b/src/api/python/cvc4.pxi
@@ -749,19 +749,11 @@ cdef class Solver:
explanation = r.getUnknownExplanation().decode()
return Result(name, explanation)
- def checkValid(self):
- cdef c_Result r = self.csolver.checkValid()
- name = r.toString().decode()
- explanation = ""
- if r.isValidUnknown():
- explanation = r.getUnknownExplanation().decode()
- return Result(name, explanation)
-
@expand_list_arg(num_req_args=0)
- def checkValidAssuming(self, *assumptions):
+ def checkEntailed(self, *assumptions):
'''
Supports the following arguments:
- Result checkValidAssuming(List[Term] assumptions)
+ Result checkEntailed(List[Term] assumptions)
where assumptions can also be comma-separated arguments of
type (boolean) Term
@@ -771,10 +763,10 @@ cdef class Solver:
cdef vector[c_Term] v
for a in assumptions:
v.push_back((<Term?> a).cterm)
- r = self.csolver.checkValidAssuming(<const vector[c_Term]&> v)
+ r = self.csolver.checkEntailed(<const vector[c_Term]&> v)
name = r.toString().decode()
explanation = ""
- if r.isValidUnknown():
+ if r.isEntailmentUnknown():
explanation = r.getUnknownExplanation().decode()
return Result(name, explanation)
diff --git a/src/base/configuration.cpp b/src/base/configuration.cpp
index f907f212f..aed835f3f 100644
--- a/src/base/configuration.cpp
+++ b/src/base/configuration.cpp
@@ -50,10 +50,6 @@ bool Configuration::isStatisticsBuild() {
return IS_STATISTICS_BUILD;
}
-bool Configuration::isReplayBuild() {
- return IS_REPLAY_BUILD;
-}
-
bool Configuration::isTracingBuild() {
return IS_TRACING_BUILD;
}
diff --git a/src/base/configuration.h b/src/base/configuration.h
index 60cdd5a9c..72ccb2301 100644
--- a/src/base/configuration.h
+++ b/src/base/configuration.h
@@ -47,8 +47,6 @@ public:
static bool isStatisticsBuild();
- static bool isReplayBuild();
-
static bool isTracingBuild();
static bool isDumpingBuild();
diff --git a/src/base/configuration_private.h b/src/base/configuration_private.h
index f3e76d53b..77db0b51c 100644
--- a/src/base/configuration_private.h
+++ b/src/base/configuration_private.h
@@ -36,12 +36,6 @@ namespace CVC4 {
# define IS_STATISTICS_BUILD false
#endif /* CVC4_STATISTICS_ON */
-#ifdef CVC4_REPLAY
-# define IS_REPLAY_BUILD true
-#else /* CVC4_REPLAY */
-# define IS_REPLAY_BUILD false
-#endif /* CVC4_REPLAY */
-
#ifdef CVC4_TRACING
# define IS_TRACING_BUILD true
#else /* CVC4_TRACING */
diff --git a/src/bindings/java/CMakeLists.txt b/src/bindings/java/CMakeLists.txt
index 344387ed9..c5abf9b27 100644
--- a/src/bindings/java/CMakeLists.txt
+++ b/src/bindings/java/CMakeLists.txt
@@ -65,7 +65,6 @@ set(gen_java_files
${CMAKE_CURRENT_BINARY_DIR}/ExprHashFunction.java
${CMAKE_CURRENT_BINARY_DIR}/ExprManager.java
${CMAKE_CURRENT_BINARY_DIR}/ExprManagerMapCollection.java
- ${CMAKE_CURRENT_BINARY_DIR}/ExprStream.java
${CMAKE_CURRENT_BINARY_DIR}/FloatingPoint.java
${CMAKE_CURRENT_BINARY_DIR}/FloatingPointConvertSort.java
${CMAKE_CURRENT_BINARY_DIR}/FloatingPointSize.java
@@ -112,6 +111,8 @@ set(gen_java_files
${CMAKE_CURRENT_BINARY_DIR}/RecordUpdate.java
${CMAKE_CURRENT_BINARY_DIR}/RecordUpdateHashFunction.java
${CMAKE_CURRENT_BINARY_DIR}/RecoverableModalException.java
+ ${CMAKE_CURRENT_BINARY_DIR}/RegExpLoop.java
+ ${CMAKE_CURRENT_BINARY_DIR}/RegExpRepeat.java
${CMAKE_CURRENT_BINARY_DIR}/RegExpType.java
${CMAKE_CURRENT_BINARY_DIR}/Result.java
${CMAKE_CURRENT_BINARY_DIR}/RoundingMode.java
diff --git a/src/cvc4.i b/src/cvc4.i
index f9f8f5743..01fd088a8 100644
--- a/src/cvc4.i
+++ b/src/cvc4.i
@@ -278,6 +278,7 @@ std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
%include "util/result.i"
%include "util/sexpr.i"
%include "util/statistics.i"
+%include "util/string.i"
%include "util/tuple.i"
%include "util/unsafe_interrupt_exception.i"
@@ -300,7 +301,6 @@ std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
// The remainder of the includes:
%include "expr/expr.i"
%include "expr/expr_manager.i"
-%include "expr/expr_stream.i"
%include "expr/variable_type_map.i"
%include "options/option_exception.i"
%include "options/options.i"
diff --git a/src/expr/CMakeLists.txt b/src/expr/CMakeLists.txt
index d1faa8ffb..a308e536c 100644
--- a/src/expr/CMakeLists.txt
+++ b/src/expr/CMakeLists.txt
@@ -12,7 +12,6 @@ libcvc4_add_sources(
expr_iomanip.cpp
expr_iomanip.h
expr_manager_scope.h
- expr_stream.h
kind_map.h
match_trie.cpp
match_trie.h
@@ -29,6 +28,8 @@ libcvc4_add_sources(
node_self_iterator.h
node_trie.cpp
node_trie.h
+ node_traversal.cpp
+ node_traversal.h
node_value.cpp
node_value.h
node_visitor.h
diff --git a/src/expr/expr_stream.h b/src/expr/expr_stream.h
deleted file mode 100644
index d31e8e4fc..000000000
--- a/src/expr/expr_stream.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/********************* */
-/*! \file expr_stream.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A stream interface for expressions
- **
- ** A stream interface for expressions.
- **/
-
-#include "cvc4_public.h"
-
-#ifndef CVC4__EXPR_STREAM_H
-#define CVC4__EXPR_STREAM_H
-
-#include "expr/expr.h"
-
-namespace CVC4 {
-
-/**
- * A pure-virtual stream interface for expressions. Can be used to
- * communicate streams of expressions between different parts of CVC4.
- */
-class CVC4_PUBLIC ExprStream {
-public:
- /** Virtual destructor; this implementation does nothing. */
- virtual ~ExprStream() {}
-
- /**
- * Get the next expression in the stream (advancing the stream
- * pointer as a side effect.)
- */
- virtual Expr nextExpr() = 0;
-};/* class ExprStream */
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__EXPR_STREAM_H */
-
diff --git a/src/expr/expr_stream.i b/src/expr/expr_stream.i
deleted file mode 100644
index f1144623b..000000000
--- a/src/expr/expr_stream.i
+++ /dev/null
@@ -1,5 +0,0 @@
-%{
-#include "expr/expr_stream.h"
-%}
-
-%include "expr/expr_stream.h"
diff --git a/src/expr/metakind_template.h b/src/expr/metakind_template.h
index c4d35b7dc..fb1626adb 100644
--- a/src/expr/metakind_template.h
+++ b/src/expr/metakind_template.h
@@ -203,20 +203,6 @@ Kind operatorToKind(::CVC4::expr::NodeValue* nv);
#line 205 "${template}"
-namespace theory {
-
-static inline bool useTheoryValidate(std::string theory) {
-${use_theory_validations}
- return false;
-}
-
-static const char *const useTheoryHelp = "\
-The following options are valid alternate implementations for use with\n\
-the --use-theory option:\n\
-\n\
-${theory_alternate_doc}";
-
-}/* CVC4::theory namespace */
}/* CVC4 namespace */
#endif /* CVC4__NODE_MANAGER_NEEDS_CONSTANT_MAP */
diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind
index fe8a152df..e2a733ec8 100755
--- a/src/expr/mkmetakind
+++ b/src/expr/mkmetakind
@@ -50,9 +50,6 @@ metakind_ubchildren=
metakind_lbchildren=
metakind_operatorKinds=
-use_theory_validations=
-theory_alternate_doc=
-
seen_theory=false
seen_theory_builtin=false
@@ -108,13 +105,6 @@ function alternate {
theory_header="$4"
theory_includes="${theory_includes}#include \"$theory_header\"
"
-
- use_theory_validations="${use_theory_validations}
- if(theory == \"$name\") {
- return true;
- }"
- theory_alternate_doc="$theory_alternate_doc$name - alternate implementation for $theory_id\\n\\
-"
}
function properties {
@@ -410,10 +400,6 @@ check_builtin_theory_seen
nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
-if [ -z "$theory_alternate_doc" ]; then
- theory_alternate_doc="[none defined]"
-fi
-
text=$(cat "$template")
for var in \
metakind_includes \
@@ -428,8 +414,6 @@ for var in \
metakind_ubchildren \
metakind_lbchildren \
metakind_operatorKinds \
- use_theory_validations \
- theory_alternate_doc \
template \
; do
eval text="\${text//\\\$\\{$var\\}/\${$var}}"
diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp
index 5d409f748..16ffd8306 100644
--- a/src/expr/node_manager.cpp
+++ b/src/expr/node_manager.cpp
@@ -575,6 +575,42 @@ TypeNode NodeManager::RecTypeCache::getRecordType( NodeManager * nm, const Recor
}
}
+TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts)
+{
+ Assert(sorts.size() >= 2);
+ CheckArgument(!sorts[sorts.size() - 1].isFunction(),
+ sorts[sorts.size() - 1],
+ "must flatten function types");
+ return mkTypeNode(kind::FUNCTION_TYPE, sorts);
+}
+
+TypeNode NodeManager::mkPredicateType(const std::vector<TypeNode>& sorts)
+{
+ Assert(sorts.size() >= 1);
+ std::vector<TypeNode> sortNodes;
+ sortNodes.insert(sortNodes.end(), sorts.begin(), sorts.end());
+ sortNodes.push_back(booleanType());
+ return mkFunctionType(sortNodes);
+}
+
+TypeNode NodeManager::mkFunctionType(const TypeNode& domain,
+ const TypeNode& range)
+{
+ std::vector<TypeNode> sorts;
+ sorts.push_back(domain);
+ sorts.push_back(range);
+ return mkFunctionType(sorts);
+}
+
+TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes,
+ const TypeNode& range)
+{
+ Assert(argTypes.size() >= 1);
+ std::vector<TypeNode> sorts(argTypes);
+ sorts.push_back(range);
+ return mkFunctionType(sorts);
+}
+
TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
std::vector< TypeNode > ts;
Debug("tuprec-debug") << "Make tuple type : ";
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index eced00c48..2e8f40fff 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -807,7 +807,7 @@ public:
* @param range the range type
* @returns the functional type domain -> range
*/
- inline TypeNode mkFunctionType(const TypeNode& domain, const TypeNode& range);
+ TypeNode mkFunctionType(const TypeNode& domain, const TypeNode& range);
/**
* Make a function type with input types from
@@ -817,8 +817,8 @@ public:
* @param range the range type
* @returns the functional type (argTypes[0], ..., argTypes[n]) -> range
*/
- inline TypeNode mkFunctionType(const std::vector<TypeNode>& argTypes,
- const TypeNode& range);
+ TypeNode mkFunctionType(const std::vector<TypeNode>& argTypes,
+ const TypeNode& range);
/**
* Make a function type with input types from
@@ -826,7 +826,7 @@ public:
* <code>sorts[sorts.size()-1]</code>. <code>sorts</code> must have
* at least 2 elements.
*/
- inline TypeNode mkFunctionType(const std::vector<TypeNode>& sorts);
+ TypeNode mkFunctionType(const std::vector<TypeNode>& sorts);
/**
* Make a predicate type with input types from
@@ -834,7 +834,7 @@ public:
* <code>BOOLEAN</code>. <code>sorts</code> must have at least one
* element.
*/
- inline TypeNode mkPredicateType(const std::vector<TypeNode>& sorts);
+ TypeNode mkPredicateType(const std::vector<TypeNode>& sorts);
/**
* Make a tuple type with types from
@@ -1086,52 +1086,6 @@ inline TypeNode NodeManager::builtinOperatorType() {
return TypeNode(mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE));
}
-/** Make a function type from domain to range. */
-inline TypeNode NodeManager::mkFunctionType(const TypeNode& domain, const TypeNode& range) {
- std::vector<TypeNode> sorts;
- sorts.push_back(domain);
- sorts.push_back(range);
- return mkFunctionType(sorts);
-}
-
-inline TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes, const TypeNode& range) {
- Assert(argTypes.size() >= 1);
- std::vector<TypeNode> sorts(argTypes);
- sorts.push_back(range);
- return mkFunctionType(sorts);
-}
-
-inline TypeNode
-NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts) {
- Assert(sorts.size() >= 2);
- std::vector<TypeNode> sortNodes;
- for (unsigned i = 0; i < sorts.size(); ++ i) {
- CheckArgument(sorts[i].isFirstClass(),
- sorts,
- "cannot create function types for argument types that are "
- "not first-class. Try option --uf-ho.");
- sortNodes.push_back(sorts[i]);
- }
- CheckArgument(!sorts[sorts.size()-1].isFunction(), sorts[sorts.size()-1],
- "must flatten function types");
- return mkTypeNode(kind::FUNCTION_TYPE, sortNodes);
-}
-
-inline TypeNode
-NodeManager::mkPredicateType(const std::vector<TypeNode>& sorts) {
- Assert(sorts.size() >= 1);
- std::vector<TypeNode> sortNodes;
- for (unsigned i = 0; i < sorts.size(); ++ i) {
- CheckArgument(sorts[i].isFirstClass(),
- sorts,
- "cannot create predicate types for argument types that are "
- "not first-class. Try option --uf-ho.");
- sortNodes.push_back(sorts[i]);
- }
- sortNodes.push_back(booleanType());
- return mkTypeNode(kind::FUNCTION_TYPE, sortNodes);
-}
-
inline TypeNode NodeManager::mkSExprType(const std::vector<TypeNode>& types) {
std::vector<TypeNode> typeNodes;
for (unsigned i = 0; i < types.size(); ++ i) {
diff --git a/src/expr/node_traversal.cpp b/src/expr/node_traversal.cpp
new file mode 100644
index 000000000..9e7a82c24
--- /dev/null
+++ b/src/expr/node_traversal.cpp
@@ -0,0 +1,150 @@
+/********************* */
+/*! \file node_traversal.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Alex Ozdemir
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Iterators for traversing nodes.
+ **/
+
+#include "node_traversal.h"
+
+namespace CVC4 {
+
+NodeDfsIterator::NodeDfsIterator(TNode n, bool postorder)
+ : d_stack{n},
+ d_visited(),
+ d_postorder(postorder),
+ d_current(TNode())
+{
+}
+
+NodeDfsIterator::NodeDfsIterator(bool postorder)
+ : d_stack(),
+ d_visited(),
+ d_postorder(postorder),
+ d_current(TNode())
+{
+}
+
+NodeDfsIterator& NodeDfsIterator::operator++()
+{
+ // If we were just constructed, advance to first visit, **before**
+ // advancing past it to the next visit (below).
+ initializeIfUninitialized();
+
+ // Advance to the next visit
+ advanceToNextVisit();
+ return *this;
+}
+
+NodeDfsIterator NodeDfsIterator::operator++(int)
+{
+ NodeDfsIterator copyOfOld(*this);
+ ++*this;
+ return copyOfOld;
+}
+
+TNode& NodeDfsIterator::operator*()
+{
+ // If we were just constructed, advance to first visit
+ initializeIfUninitialized();
+ Assert(!d_current.isNull());
+
+ return d_current;
+}
+
+bool NodeDfsIterator::operator==(const NodeDfsIterator& other) const
+{
+ // The stack and current node uniquely represent traversal state. We need not
+ // use the scheduled node set.
+ //
+ // Users should not compare iterators for traversals of different nodes.
+ Assert(d_postorder == other.d_postorder);
+ return d_stack == other.d_stack && d_current == other.d_current;
+}
+
+bool NodeDfsIterator::operator!=(const NodeDfsIterator& other) const
+{
+ return !(*this == other);
+}
+
+void NodeDfsIterator::advanceToNextVisit()
+{
+ // While a node is enqueued and we're not at the right visit type
+ while (!d_stack.empty())
+ {
+ TNode back = d_stack.back();
+ auto visitEntry = d_visited.find(back);
+ if (visitEntry == d_visited.end())
+ {
+ // if we haven't pre-visited this node, pre-visit it
+ d_visited[back] = false;
+ d_current = back;
+ // Use integer underflow to reverse-iterate
+ for (size_t n = back.getNumChildren(), i = n - 1; i < n; --i)
+ {
+ d_stack.push_back(back[i]);
+ }
+ if (!d_postorder)
+ {
+ return;
+ }
+ }
+ else if (!d_postorder || visitEntry->second)
+ {
+ // if we're previsiting or we've already post-visited this node: skip it
+ d_stack.pop_back();
+ }
+ else
+ {
+ // otherwise, this is a post-visit
+ visitEntry->second = true;
+ d_current = back;
+ d_stack.pop_back();
+ return;
+ }
+ }
+ // We're at the end of the traversal: nullify the current node to agree
+ // with the "end" iterator.
+ d_current = TNode();
+}
+
+void NodeDfsIterator::initializeIfUninitialized()
+{
+ if (d_current.isNull())
+ {
+ advanceToNextVisit();
+ }
+}
+
+NodeDfsIterable::NodeDfsIterable(TNode n) : d_node(n), d_postorder(true) {}
+
+NodeDfsIterable& NodeDfsIterable::inPostorder()
+{
+ d_postorder = true;
+ return *this;
+}
+
+NodeDfsIterable& NodeDfsIterable::inPreorder()
+{
+ d_postorder = false;
+ return *this;
+}
+
+NodeDfsIterator NodeDfsIterable::begin() const
+{
+ return NodeDfsIterator(d_node, d_postorder);
+}
+
+NodeDfsIterator NodeDfsIterable::end() const
+{
+ return NodeDfsIterator(d_postorder);
+}
+
+} // namespace CVC4
diff --git a/src/expr/node_traversal.h b/src/expr/node_traversal.h
new file mode 100644
index 000000000..fffc1d746
--- /dev/null
+++ b/src/expr/node_traversal.h
@@ -0,0 +1,131 @@
+/********************* */
+/*! \file node_traversal.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Alex Ozdemir
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Iterators for traversing nodes.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__NODE_TRAVERSAL_H
+#define CVC4__EXPR__NODE_TRAVERSAL_H
+
+#include <cstddef>
+#include <iterator>
+#include <unordered_map>
+#include <vector>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+
+// Iterator for traversing a node in post-order
+// It does DAG-traversal, so indentical sub-nodes will be visited once only.
+class NodeDfsIterator
+{
+ public:
+ // STL type definitions for an iterator
+ using value_type = TNode;
+ using pointer = TNode*;
+ using reference = TNode&;
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+
+ // Construct a traversal iterator beginning at `n`
+ NodeDfsIterator(TNode n, bool postorder);
+ // Construct an end-of-traversal iterator
+ NodeDfsIterator(bool postorder);
+
+ // Move/copy construction and assignment. Destructor.
+ NodeDfsIterator(NodeDfsIterator&&) = default;
+ NodeDfsIterator& operator=(NodeDfsIterator&&) = default;
+ NodeDfsIterator(NodeDfsIterator&) = default;
+ NodeDfsIterator& operator=(NodeDfsIterator&) = default;
+ ~NodeDfsIterator() = default;
+
+ // Preincrement
+ NodeDfsIterator& operator++();
+ // Postincrement
+ NodeDfsIterator operator++(int);
+ // Dereference
+ reference operator*();
+ // Equals
+ bool operator==(const NodeDfsIterator&) const;
+ // Not equals
+ bool operator!=(const NodeDfsIterator&) const;
+
+ private:
+ // While we're not at an appropriate visit (see d_postorder), advance.
+ // In each step:
+ // * enqueue children of a not-yet-pre-visited node (and mark it
+ // previsited)
+ // * pop a not-yet-post-visited node (and mark it post-visited)
+ // * pop an already post-visited node.
+ // After calling this, `d_current` will be changed to the next node, if there
+ // is another node in the traversal.
+ void advanceToNextVisit();
+
+ // If this iterator hasn't been dereferenced or incremented yet, advance to
+ // first visit.
+ // Necessary because we are lazy and don't find our first visit node at
+ // construction time.
+ void initializeIfUninitialized();
+
+ // Stack of nodes to visit.
+ std::vector<TNode> d_stack;
+
+ // Whether (and how) we've visited a node.
+ // Absent if we haven't visited it.
+ // Set to `false` if we've already pre-visited it (enqueued its children).
+ // Set to `true` if we've also already post-visited it.
+ std::unordered_map<TNode, bool, TNodeHashFunction> d_visited;
+
+ // Whether this is a post-order iterator (the alternative is pre-order)
+ bool d_postorder;
+
+ // Whether this iterator has been initialized (advanced to its first
+ // visit)
+ bool d_initialized;
+
+ // Current referent node. A valid node to visit if non-null.
+ // Null after construction (but before first access) and at the end.
+ TNode d_current;
+};
+
+// Node wrapper that is iterable in DAG post-order
+class NodeDfsIterable
+{
+ public:
+ NodeDfsIterable(TNode n);
+
+ // Modifying the traversal order
+ // Modify this iterable to be in post-order (default)
+ NodeDfsIterable& inPostorder();
+ // Modify this iterable to be in pre-order
+ NodeDfsIterable& inPreorder();
+
+ // Move/copy construction and assignment. Destructor.
+ NodeDfsIterable(NodeDfsIterable&&) = default;
+ NodeDfsIterable& operator=(NodeDfsIterable&&) = default;
+ NodeDfsIterable(NodeDfsIterable&) = default;
+ NodeDfsIterable& operator=(NodeDfsIterable&) = default;
+ ~NodeDfsIterable() = default;
+
+ NodeDfsIterator begin() const;
+ NodeDfsIterator end() const;
+
+ private:
+ TNode d_node;
+ bool d_postorder;
+};
+
+} // namespace CVC4
+
+#endif // CVC4__EXPR__NODE_TRAVERSAL_H
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index 9db704621..323f24492 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -53,8 +53,7 @@ CommandExecutor::CommandExecutor(Options& options)
d_smtEngine(d_solver->getSmtEngine()),
d_options(options),
d_stats("driver"),
- d_result(),
- d_replayStream(nullptr)
+ d_result()
{
}
@@ -72,12 +71,6 @@ void CommandExecutor::safeFlushStatistics(int fd) const
d_stats.safeFlushInformation(fd);
}
-void CommandExecutor::setReplayStream(ExprStream* replayStream) {
- assert(d_replayStream == NULL);
- d_replayStream = replayStream;
- d_smtEngine->setReplayStream(d_replayStream);
-}
-
bool CommandExecutor::doCommand(Command* cmd)
{
if( d_options.getParseOnly() ) {
diff --git a/src/main/command_executor.h b/src/main/command_executor.h
index 3fc971f5b..a9b6d9077 100644
--- a/src/main/command_executor.h
+++ b/src/main/command_executor.h
@@ -44,17 +44,12 @@ class CommandExecutor
Options& d_options;
StatisticsRegistry d_stats;
Result d_result;
- ExprStream* d_replayStream;
public:
CommandExecutor(Options& options);
virtual ~CommandExecutor()
{
- if (d_replayStream != NULL)
- {
- delete d_replayStream;
- }
}
/**
@@ -92,8 +87,6 @@ class CommandExecutor
void flushOutputStreams();
- void setReplayStream(ExprStream* replayStream);
-
protected:
/** Executes treating cmd as a singleton */
virtual bool doCommandSingleton(CVC4::Command* cmd);
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index be2d0a0f8..92368148b 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -184,23 +184,6 @@ int runCvc4(int argc, char* argv[], Options& opts) {
// Create the command executor to execute the parsed commands
pExecutor = new CommandExecutor(opts);
- std::unique_ptr<Parser> replayParser;
- if (opts.getReplayInputFilename() != "")
- {
- std::string replayFilename = opts.getReplayInputFilename();
- ParserBuilder replayParserBuilder(
- pExecutor->getSolver(), replayFilename, opts);
-
- if( replayFilename == "-") {
- if( inputFromStdin ) {
- throw OptionException("Replay file and input file can't both be stdin.");
- }
- replayParserBuilder.withStreamInput(cin);
- }
- replayParser.reset(replayParserBuilder.build());
- pExecutor->setReplayStream(new Parser::ExprStream(replayParser.get()));
- }
-
int returnValue = 0;
{
// Timer statistic
@@ -241,10 +224,6 @@ int runCvc4(int argc, char* argv[], Options& opts) {
<< endl << endl;
Message() << Configuration::copyright() << endl;
}
- if(replayParser) {
- // have the replay parser use the declarations input interactively
- replayParser->useDeclarationsFrom(shell.getParser());
- }
while(true) {
try {
@@ -294,10 +273,6 @@ int runCvc4(int argc, char* argv[], Options& opts) {
vector< vector<Command*> > allCommands;
allCommands.push_back(vector<Command*>());
std::unique_ptr<Parser> parser(parserBuilder.build());
- if(replayParser) {
- // have the replay parser use the file's declarations
- replayParser->useDeclarationsFrom(parser.get());
- }
int needReset = 0;
// true if one of the commands was interrupted
bool interrupted = false;
@@ -453,10 +428,6 @@ int runCvc4(int argc, char* argv[], Options& opts) {
}
std::unique_ptr<Parser> parser(parserBuilder.build());
- if(replayParser) {
- // have the replay parser use the file's declarations
- replayParser->useDeclarationsFrom(parser.get());
- }
bool interrupted = false;
while (status)
{
diff --git a/src/options/CMakeLists.txt b/src/options/CMakeLists.txt
index 4fb331e50..4909d7d43 100644
--- a/src/options/CMakeLists.txt
+++ b/src/options/CMakeLists.txt
@@ -47,7 +47,6 @@ set(options_toml_files
decision_options.toml
expr_options.toml
fp_options.toml
- idl_options.toml
main_options.toml
parser_options.toml
printer_options.toml
diff --git a/src/options/arith_options.toml b/src/options/arith_options.toml
index ab8164130..1c0351bcb 100644
--- a/src/options/arith_options.toml
+++ b/src/options/arith_options.toml
@@ -551,3 +551,12 @@ header = "options/arith_options.h"
default = "true"
read_only = true
help = "whether to increment the precision for irrational function constraints"
+
+[[option]]
+ name = "brabTest"
+ category = "regular"
+ long = "arith-brab"
+ type = "bool"
+ default = "true"
+ read_only = true
+ help = "whether to use simple rounding, similar to a unit-cube test, for integers"
diff --git a/src/options/datatypes_options.toml b/src/options/datatypes_options.toml
index 82e833506..ac371efeb 100644
--- a/src/options/datatypes_options.toml
+++ b/src/options/datatypes_options.toml
@@ -32,15 +32,6 @@ header = "options/datatypes_options.h"
help = "do binary splits for datatype constructor types"
[[option]]
- name = "dtRefIntro"
- category = "regular"
- long = "dt-ref-sk-intro"
- type = "bool"
- default = "false"
- read_only = true
- help = "introduce reference skolems for shorter explanations"
-
-[[option]]
name = "cdtBisimilar"
category = "regular"
long = "cdt-bisimilar"
diff --git a/src/options/idl_options.toml b/src/options/idl_options.toml
deleted file mode 100644
index d3bee7018..000000000
--- a/src/options/idl_options.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-id = "IDL"
-name = "Idl"
-header = "options/idl_options.h"
-
-[[option]]
- name = "idlRewriteEq"
- category = "regular"
- long = "idl-rewrite-equalities"
- type = "bool"
- default = "false"
- help = "enable rewriting equalities into two inequalities in IDL solver (default is disabled)"
diff --git a/src/options/options.h b/src/options/options.h
index ad2729205..3d1e67aba 100644
--- a/src/options/options.h
+++ b/src/options/options.h
@@ -67,9 +67,6 @@ class CVC4_PUBLIC Options {
/** Listeners for options::tlimit-per. */
ListenerCollection d_rlimitPerListeners;
- /** Listeners for options::useTheoryList. */
- ListenerCollection d_useTheoryListListeners;
-
/** Listeners for options::defaultExprDepth. */
ListenerCollection d_setDefaultExprDepthListeners;
@@ -94,10 +91,6 @@ class CVC4_PUBLIC Options {
/** Listeners for options::diagnosticChannelName. */
ListenerCollection d_setDiagnosticChannelListeners;
- /** Listeners for options::replayFilename. */
- ListenerCollection d_setReplayFilenameListeners;
-
-
static ListenerCollection::Registration* registerAndNotify(
ListenerCollection& collection, Listener* listener, bool notify);
@@ -231,7 +224,6 @@ public:
std::ostream* getOut();
std::ostream* getOutConst() const; // TODO: Remove this.
std::string getBinaryName() const;
- std::string getReplayInputFilename() const;
unsigned getParseStep() const;
// TODO: Document these.
@@ -382,19 +374,6 @@ public:
Listener* listener, bool notifyIfSet);
/**
- * Registers a listener for options::useTheoryList being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerUseTheoryListListener(
- Listener* listener, bool notifyIfSet);
-
-
- /**
* Registers a listener for options::defaultExprDepth being set.
*
* If notifyIfSet is true, this calls notify on the listener
@@ -490,18 +469,6 @@ public:
ListenerCollection::Registration* registerSetDiagnosticOutputChannelListener(
Listener* listener, bool notifyIfSet);
- /**
- * Registers a listener for options::replayLogFilename being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetReplayLogFilename(
- Listener* listener, bool notifyIfSet);
-
/** Sends a std::flush to getErr(). */
void flushErr();
diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp
index 3e6c4da3c..7fcc8f2ae 100644
--- a/src/options/options_handler.cpp
+++ b/src/options/options_handler.cpp
@@ -244,20 +244,6 @@ void OptionsHandler::setBitblastAig(std::string option, bool arg)
}
}
-// theory/options_handlers.h
-std::string OptionsHandler::handleUseTheoryList(std::string option, std::string optarg) {
- std::string currentList = options::useTheoryList();
- if(currentList.empty()){
- return optarg;
- } else {
- return currentList +','+ optarg;
- }
-}
-
-void OptionsHandler::notifyUseTheoryList(std::string option) {
- d_options->d_useTheoryListListeners.notify();
-}
-
// printer/options_handlers.h
const std::string OptionsHandler::s_instFormatHelp = "\
Inst format modes currently supported by the --inst-format option:\n\
@@ -340,23 +326,6 @@ void OptionsHandler::notifySetDiagnosticOutputChannel(std::string option) {
d_options->d_setDiagnosticChannelListeners.notify();
}
-
-std::string OptionsHandler::checkReplayFilename(std::string option, std::string optarg) {
-#ifdef CVC4_REPLAY
- if(optarg == "") {
- throw OptionException (std::string("Bad file name for --replay"));
- } else {
- return optarg;
- }
-#else /* CVC4_REPLAY */
- throw OptionException("The replay feature was disabled in this build of CVC4.");
-#endif /* CVC4_REPLAY */
-}
-
-void OptionsHandler::notifySetReplayLogFilename(std::string option) {
- d_options->d_setReplayFilenameListeners.notify();
-}
-
void OptionsHandler::statsEnabledBuild(std::string option, bool value)
{
#ifndef CVC4_STATISTICS_ON
@@ -453,7 +422,6 @@ void OptionsHandler::showConfiguration(std::string option) {
print_config_cond("debug code", Configuration::isDebugBuild());
print_config_cond("statistics", Configuration::isStatisticsBuild());
- print_config_cond("replay", Configuration::isReplayBuild());
print_config_cond("tracing", Configuration::isTracingBuild());
print_config_cond("dumping", Configuration::isDumpingBuild());
print_config_cond("muzzled", Configuration::isMuzzledBuild());
diff --git a/src/options/options_handler.h b/src/options/options_handler.h
index a395bb453..396b2c8ea 100644
--- a/src/options/options_handler.h
+++ b/src/options/options_handler.h
@@ -74,10 +74,6 @@ public:
void setBitblastAig(std::string option, bool arg);
- // theory/options_handlers.h
- void notifyUseTheoryList(std::string option);
- std::string handleUseTheoryList(std::string option, std::string optarg);
-
// printer/options_handlers.h
InstFormatMode stringToInstFormatMode(std::string option, std::string optarg);
@@ -96,8 +92,6 @@ public:
void notifyDumpToFile(std::string option);
void notifySetRegularOutputChannel(std::string option);
void notifySetDiagnosticOutputChannel(std::string option);
- std::string checkReplayFilename(std::string option, std::string optarg);
- void notifySetReplayLogFilename(std::string option);
void statsEnabledBuild(std::string option, bool value);
diff --git a/src/options/options_public_functions.cpp b/src/options/options_public_functions.cpp
index d1022c51c..bae60a374 100644
--- a/src/options/options_public_functions.cpp
+++ b/src/options/options_public_functions.cpp
@@ -187,10 +187,6 @@ std::string Options::getBinaryName() const{
return (*this)[options::binary_name];
}
-std::string Options::getReplayInputFilename() const{
- return (*this)[options::replayInputFilename];
-}
-
unsigned Options::getParseStep() const{
return (*this)[options::parseStep];
}
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index dad4f13a1..48b6a66dd 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -317,13 +317,6 @@ ListenerCollection::Registration* Options::registerRlimitPerListener(
return registerAndNotify(d_rlimitPerListeners, listener, notify);
}
-ListenerCollection::Registration* Options::registerUseTheoryListListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::useTheoryList);
- return registerAndNotify(d_useTheoryListListeners, listener, notify);
-}
-
ListenerCollection::Registration* Options::registerSetDefaultExprDepthListener(
Listener* listener, bool notifyIfSet)
{
@@ -382,14 +375,6 @@ Options::registerSetDiagnosticOutputChannelListener(
return registerAndNotify(d_setDiagnosticChannelListeners, listener, notify);
}
-ListenerCollection::Registration*
-Options::registerSetReplayLogFilename(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::replayLogFilename);
- return registerAndNotify(d_setReplayFilenameListeners, listener, notify);
-}
-
${custom_handlers}$
diff --git a/src/options/smt_options.toml b/src/options/smt_options.toml
index 51df591d7..a0e3014b0 100644
--- a/src/options/smt_options.toml
+++ b/src/options/smt_options.toml
@@ -620,27 +620,6 @@ header = "options/smt_options.h"
read_only = true
help = "amount of resources spent for each sat conflict (bitvectors)"
-# --replay is currently broken; don't document it for 1.0
-[[option]]
- name = "replayInputFilename"
- category = "undocumented"
- long = "replay=FILE"
- type = "std::string"
- handler = "checkReplayFilename"
- read_only = true
- help = "replay decisions from file"
-
-# --replay is currently broken; don't document it for 1.0
-[[option]]
- name = "replayLogFilename"
- category = "undocumented"
- long = "replay-log=FILE"
- type = "std::string"
- handler = "checkReplayFilename"
- notifies = ["notifySetReplayLogFilename", "notifyBeforeSearch"]
- read_only = true
- help = "replay decisions from file"
-
[[option]]
name = "forceNoLimitCpuWhileDump"
category = "regular"
diff --git a/src/options/theory_options.toml b/src/options/theory_options.toml
index 13c3d5cfb..84c994c3f 100644
--- a/src/options/theory_options.toml
+++ b/src/options/theory_options.toml
@@ -19,17 +19,6 @@ header = "options/theory_options.h"
help = "Type variables as uninterpreted, type constants by theory, equalities by the parametric theory."
[[option]]
- name = "useTheoryList"
- smt_name = "use-theory"
- category = "regular"
- long = "use-theory=NAME"
- type = "std::string"
- handler = "handleUseTheoryList"
- notifies = ["notifyUseTheoryList"]
- read_only = true
- help = "use alternate theory implementation NAME (--use-theory=help for a list). This option may be repeated or a comma separated list."
-
-[[option]]
name = "assignFunctionValues"
category = "regular"
long = "assign-function-values"
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 82c0581ce..32604d03f 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -114,6 +114,7 @@ tokens {
FORALL_TOK = 'FORALL';
EXISTS_TOK = 'EXISTS';
+ CHOICE_TOK = 'CHOICE';
PATTERN_TOK = 'PATTERN';
LAMBDA_TOK = 'LAMBDA';
@@ -343,7 +344,8 @@ int getOperatorPrecedence(int type) {
case IMPLIES_TOK: return 30;// right-to-left
case IFF_TOK: return 31;
case FORALL_TOK:
- case EXISTS_TOK: return 32;
+ case EXISTS_TOK:
+ case CHOICE_TOK: return 32;
case ASSIGN_TOK:
case IN_TOK: return 33;
@@ -1322,8 +1324,6 @@ restrictedTypePossiblyFunctionLHS[CVC4::api::Sort& t,
* declared in the outer context. What follows isn't quite right,
* though, since type aliases and function definitions should be
* retained in the set of current declarations. */
- { /*symtab = PARSER_STATE->getSymbolTable();
- PARSER_STATE->useDeclarationsFrom(new SymbolTable());*/ }
formula[f] ( COMMA formula[f2] )? RPAREN
{
PARSER_STATE->unimplementedFeature("predicate subtyping not supported in this release");
@@ -1465,7 +1465,7 @@ prefixFormula[CVC4::api::Term& f]
api::Term ipl;
}
/* quantifiers */
- : ( FORALL_TOK { k = api::FORALL; } | EXISTS_TOK { k = api::EXISTS; } )
+ : ( FORALL_TOK { k = api::FORALL; } | EXISTS_TOK { k = api::EXISTS; } | CHOICE_TOK { k = api::CHOICE; } )
{ PARSER_STATE->pushScope(); } LPAREN
boundVarDecl[ids,t]
{ for(std::vector<std::string>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
@@ -2072,8 +2072,11 @@ stringTerm[CVC4::api::Term& f]
{ f = MK_TERM(CVC4::api::REGEXP_OPT, f); }
| REGEXP_RANGE_TOK LPAREN formula[f] COMMA formula[f2] RPAREN
{ f = MK_TERM(CVC4::api::REGEXP_RANGE, f, f2); }
- | REGEXP_LOOP_TOK LPAREN formula[f] COMMA formula[f2] COMMA formula[f3] RPAREN
- { f = MK_TERM(CVC4::api::REGEXP_LOOP, f, f2, f3); }
+ | REGEXP_LOOP_TOK LPAREN formula[f] COMMA lo=numeral COMMA hi=numeral RPAREN
+ {
+ api::Op lop = SOLVER->mkOp(CVC4::api::REGEXP_LOOP, lo, hi);
+ f = MK_TERM(lop, f);
+ }
| REGEXP_COMPLEMENT_TOK LPAREN formula[f] RPAREN
{ f = MK_TERM(CVC4::api::REGEXP_COMPLEMENT, f); }
| REGEXP_EMPTY_TOK
@@ -2083,7 +2086,7 @@ stringTerm[CVC4::api::Term& f]
/* string literal */
| str[s]
- { f = SOLVER->mkString(s, true); }
+ { f = PARSER_STATE->mkStringConstant(s); }
| setsTerm[f]
;
diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp
index b36f36a93..5dca92370 100644
--- a/src/parser/parser.cpp
+++ b/src/parser/parser.cpp
@@ -757,5 +757,153 @@ void Parser::attributeNotSupported(const std::string& attr) {
}
}
+std::vector<unsigned> Parser::processAdHocStringEsc(const std::string& s)
+{
+ std::vector<unsigned> str;
+ unsigned i = 0;
+ while (i < s.size())
+ {
+ // get the current character
+ if (s[i] != '\\')
+ {
+ // don't worry about printable here
+ str.push_back(static_cast<unsigned>(s[i]));
+ ++i;
+ continue;
+ }
+ // slash is always escaped
+ ++i;
+ if (i >= s.size())
+ {
+ // slash cannot be the last character if we are parsing escape sequences
+ std::stringstream serr;
+ serr << "Escape sequence at the end of string: \"" << s
+ << "\" should be handled by lexer";
+ parseError(serr.str());
+ }
+ switch (s[i])
+ {
+ case 'n':
+ {
+ str.push_back(static_cast<unsigned>('\n'));
+ i++;
+ }
+ break;
+ case 't':
+ {
+ str.push_back(static_cast<unsigned>('\t'));
+ i++;
+ }
+ break;
+ case 'v':
+ {
+ str.push_back(static_cast<unsigned>('\v'));
+ i++;
+ }
+ break;
+ case 'b':
+ {
+ str.push_back(static_cast<unsigned>('\b'));
+ i++;
+ }
+ break;
+ case 'r':
+ {
+ str.push_back(static_cast<unsigned>('\r'));
+ i++;
+ }
+ break;
+ case 'f':
+ {
+ str.push_back(static_cast<unsigned>('\f'));
+ i++;
+ }
+ break;
+ case 'a':
+ {
+ str.push_back(static_cast<unsigned>('\a'));
+ i++;
+ }
+ break;
+ case '\\':
+ {
+ str.push_back(static_cast<unsigned>('\\'));
+ i++;
+ }
+ break;
+ case 'x':
+ {
+ bool isValid = false;
+ if (i + 2 < s.size())
+ {
+ if (std::isxdigit(s[i + 1]) && std::isxdigit(s[i + 2]))
+ {
+ std::stringstream shex;
+ shex << s[i + 1] << s[i + 2];
+ unsigned val;
+ shex >> std::hex >> val;
+ str.push_back(val);
+ i += 3;
+ isValid = true;
+ }
+ }
+ if (!isValid)
+ {
+ std::stringstream serr;
+ serr << "Illegal String Literal: \"" << s
+ << "\", must have two digits after \\x";
+ parseError(serr.str());
+ }
+ }
+ break;
+ default:
+ {
+ if (std::isdigit(s[i]))
+ {
+ // octal escape sequences TODO : revisit (issue #1251).
+ unsigned num = static_cast<unsigned>(s[i]) - 48;
+ bool flag = num < 4;
+ if (i + 1 < s.size() && num < 8 && std::isdigit(s[i + 1])
+ && s[i + 1] < '8')
+ {
+ num = num * 8 + static_cast<unsigned>(s[i + 1]) - 48;
+ if (flag && i + 2 < s.size() && std::isdigit(s[i + 2])
+ && s[i + 2] < '8')
+ {
+ num = num * 8 + static_cast<unsigned>(s[i + 2]) - 48;
+ str.push_back(num);
+ i += 3;
+ }
+ else
+ {
+ str.push_back(num);
+ i += 2;
+ }
+ }
+ else
+ {
+ str.push_back(num);
+ i++;
+ }
+ }
+ }
+ }
+ }
+ return str;
+}
+
+Expr Parser::mkStringConstant(const std::string& s)
+{
+ ExprManager* em = d_solver->getExprManager();
+ if (em->getOptions().getInputLanguage()
+ == language::input::LANG_SMTLIB_V2_6_1)
+ {
+ return d_solver->mkString(s, true).getExpr();
+ }
+ // otherwise, we must process ad-hoc escape sequences
+ std::vector<unsigned> str = processAdHocStringEsc(s);
+ return d_solver->mkString(str).getExpr();
+}
+
} /* CVC4::parser namespace */
} /* CVC4 namespace */
diff --git a/src/parser/parser.h b/src/parser/parser.h
index ecea4d3bd..cd4105cd0 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -26,7 +26,6 @@
#include "api/cvc4cpp.h"
#include "expr/expr.h"
-#include "expr/expr_stream.h"
#include "expr/kind.h"
#include "expr/symbol_table.h"
#include "parser/input.h"
@@ -273,6 +272,9 @@ public:
return d_input;
}
+ /** Get unresolved sorts */
+ inline std::set<api::Sort>& getUnresolvedSorts() { return d_unresolved; }
+
/** Deletes and replaces the current parser input. */
void setInput(Input* input) {
delete d_input;
@@ -803,63 +805,9 @@ public:
d_globalDeclarations = flag;
}
- /**
- * Set the current symbol table used by this parser.
- * From now on, this parser will perform its definitions and
- * lookups in the declaration scope of the "parser" argument
- * (but doesn't re-delegate if the other parser's declaration scope
- * changes later). A NULL argument restores this parser's
- * "primordial" declaration scope assigned at its creation. Calling
- * p->useDeclarationsFrom(p) is a no-op.
- *
- * This feature is useful when e.g. reading out-of-band expression data:
- * 1. Parsing --replay log files produced with --replay-log.
- * 2. Perhaps a multi-query benchmark file is being single-stepped
- * with intervening queries on stdin that must reference the same
- * declaration scope(s).
- *
- * However, the feature must be used carefully. Pushes and pops
- * should be performed with the correct current declaration scope.
- * Care must be taken to match up declaration scopes, of course;
- * If variables in the deferred-to parser go out of scope, the
- * secondary parser will give errors that they are undeclared.
- * Also, an outer-scope variable shadowed by an inner-scope one of
- * the same name may be temporarily inaccessible.
- *
- * In short, caveat emptor.
- */
- inline void useDeclarationsFrom(Parser* parser) {
- if(parser == NULL) {
- d_symtab = &d_symtabAllocated;
- } else {
- d_symtab = parser->d_symtab;
- }
- }
-
- inline void useDeclarationsFrom(SymbolTable* symtab) {
- d_symtab = symtab;
- }
-
inline SymbolTable* getSymbolTable() const {
return d_symtab;
}
-
- /**
- * An expression stream interface for a parser. This stream simply
- * pulls expressions from the given Parser object.
- *
- * Here, the ExprStream base class allows a Parser (from the parser
- * library) and core components of CVC4 (in the core library) to
- * communicate without polluting the public interface or having them
- * reach into private (undocumented) interfaces.
- */
- class ExprStream : public CVC4::ExprStream {
- Parser* d_parser;
- public:
- ExprStream(Parser* parser) : d_parser(parser) {}
- ~ExprStream() { delete d_parser; }
- Expr nextExpr() override { return d_parser->nextExpression().getExpr(); }
- };/* class Parser::ExprStream */
//------------------------ operator overloading
/** is this function overloaded? */
@@ -889,6 +837,28 @@ public:
name, api::sortVectorToTypes(argTypes));
}
//------------------------ end operator overloading
+ /**
+ * Make string constant
+ *
+ * This makes the string constant based on the string s. This may involve
+ * processing ad-hoc escape sequences (if the language is not
+ * SMT-LIB 2.6.1 or higher), or otherwise calling the solver to construct
+ * the string.
+ */
+ Expr mkStringConstant(const std::string& s);
+
+ private:
+ /** ad-hoc string escaping
+ *
+ * Returns the (internal) vector of code points corresponding to processing
+ * the escape sequences in string s. This is to support string inputs that
+ * do no comply with the SMT-LIB standard.
+ *
+ * This method handles escape sequences, including \n, \t, \v, \b, \r, \f, \a,
+ * \\, \x[N] and octal escape sequences of the form \[c1]([c2]([c3])?)? where
+ * c1, c2, c3 are digits from 0 to 7.
+ */
+ std::vector<unsigned> processAdHocStringEsc(const std::string& s);
};/* class Parser */
}/* CVC4::parser namespace */
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index ec1eae7da..1d0fb71cb 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -782,8 +782,24 @@ sygusGrammarV1[CVC4::api::Sort & ret,
Debug("parser-sygus") << " " << i << " : " << datatypes[i].getName()
<< std::endl;
}
- std::vector<api::Sort> datatypeTypes =
- PARSER_STATE->bindMutualDatatypeTypes(datatypes, false);
+
+ std::vector<CVC4::Datatype> dtypes;
+ dtypes.reserve(ndatatypes);
+
+ for (api::DatatypeDecl i : datatypes)
+ {
+ dtypes.push_back(i.getDatatype());
+ }
+
+ std::set<Type> tset =
+ api::sortSetToTypes(PARSER_STATE->getUnresolvedSorts());
+
+ std::vector<DatatypeType> datatypeTypes =
+ SOLVER->getExprManager()->mkMutualDatatypeTypes(
+ dtypes, tset, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
+
+ PARSER_STATE->getUnresolvedSorts().clear();
+
ret = datatypeTypes[0];
};
@@ -2067,6 +2083,11 @@ termAtomic[CVC4::api::Term& atomTerm]
api::Term v2 = SOLVER->mkConst(api::Sort(type2), "_emp2");
atomTerm = SOLVER->mkTerm(api::SEP_EMP, v1, v2);
}
+ | CHAR_TOK HEX_LITERAL
+ {
+ std::string hexStr = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2);
+ atomTerm = SOLVER->mkChar(hexStr);
+ }
| sym=SIMPLE_SYMBOL nonemptyNumeralList[numerals]
{
atomTerm =
@@ -2078,10 +2099,10 @@ termAtomic[CVC4::api::Term& atomTerm]
// Bit-vector constants
| HEX_LITERAL
- {
- assert(AntlrInput::tokenText($HEX_LITERAL).find("#x") == 0);
- std::string hexStr = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2);
- atomTerm = SOLVER->mkBitVector(hexStr, 16);
+ {
+ assert(AntlrInput::tokenText($HEX_LITERAL).find("#x") == 0);
+ std::string hexStr = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2);
+ atomTerm = SOLVER->mkBitVector(hexStr, 16);
}
| BINARY_LITERAL
{
@@ -2091,7 +2112,7 @@ termAtomic[CVC4::api::Term& atomTerm]
}
// String constant
- | str[s,false] { atomTerm = SOLVER->mkString(s, true); }
+ | str[s,false] { atomTerm = PARSER_STATE->mkStringConstant(s); }
// NOTE: Theory constants go here
@@ -2296,6 +2317,7 @@ quantOp[CVC4::api::Kind& kind]
}
: EXISTS_TOK { $kind = api::EXISTS; }
| FORALL_TOK { $kind = api::FORALL; }
+ | CHOICE_TOK { $kind = api::CHOICE; }
;
/**
@@ -2666,8 +2688,10 @@ ATTRIBUTE_INST_LEVEL : ':quant-inst-max-level';
// operators (NOTE: theory symbols go here)
EXISTS_TOK : 'exists';
FORALL_TOK : 'forall';
+CHOICE_TOK : { !PARSER_STATE->strictModeEnabled() }? 'choice';
EMP_TOK : { PARSER_STATE->isTheoryEnabled(theory::THEORY_SEP) }? 'emp';
+CHAR_TOK : { PARSER_STATE->isTheoryEnabled(theory::THEORY_STRINGS) }? 'char';
TUPLE_CONST_TOK: { PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }? 'mkTuple';
TUPLE_SEL_TOK: { PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }? 'tupSel';
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index 81ddae6d6..3233ee7e8 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -193,8 +193,9 @@ void Smt2::addStringOperators() {
addOperator(api::REGEXP_STAR, "re.*");
addOperator(api::REGEXP_PLUS, "re.+");
addOperator(api::REGEXP_OPT, "re.opt");
+ addIndexedOperator(api::REGEXP_REPEAT, api::REGEXP_REPEAT, "re.^");
+ addIndexedOperator(api::REGEXP_LOOP, api::REGEXP_LOOP, "re.loop");
addOperator(api::REGEXP_RANGE, "re.range");
- addOperator(api::REGEXP_LOOP, "re.loop");
addOperator(api::REGEXP_COMPLEMENT, "re.comp");
addOperator(api::REGEXP_DIFF, "re.diff");
addOperator(api::STRING_LT, "str.<");
@@ -330,7 +331,7 @@ api::Term Smt2::getExpressionForNameAndType(const std::string& name,
bool Smt2::getTesterName(api::Term cons, std::string& name)
{
- if (v2_6() && strictModeEnabled())
+ if ((v2_6() || sygus_v2()) && strictModeEnabled())
{
// 2.6 or above uses indexed tester symbols, if we are in strict mode,
// we do not automatically define is-cons for constructor cons.
@@ -744,11 +745,17 @@ bool Smt2::sygus() const
return ilang == language::input::LANG_SYGUS
|| ilang == language::input::LANG_SYGUS_V2;
}
+
bool Smt2::sygus_v1() const
{
return getLanguage() == language::input::LANG_SYGUS;
}
+bool Smt2::sygus_v2() const
+{
+ return getLanguage() == language::input::LANG_SYGUS_V2;
+}
+
void Smt2::setInfo(const std::string& flag, const SExpr& sexpr) {
// TODO: ???
}
@@ -1261,7 +1268,8 @@ void Smt2::mkSygusDatatype(api::DatatypeDecl& dt,
api::Term lbvl = makeSygusBoundVarList(dt, i, ltypes, largs);
// make the let_body
- api::Term body = applyParseOp(ops[i], largs);
+ std::vector<api::Term> largsApply = largs;
+ api::Term body = applyParseOp(ops[i], largsApply);
// replace by lambda
ParseOp pLam;
pLam.d_expr = d_solver->mkTerm(api::LAMBDA, lbvl, body);
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 0400c680f..35d088601 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -277,6 +277,8 @@ class Smt2 : public Parser
bool sygus() const;
/** Are we using the sygus version 1.0 format? */
bool sygus_v1() const;
+ /** Are we using the sygus version 2.0 format? */
+ bool sygus_v2() const;
/**
* Returns true if the language that we are parsing (SMT-LIB version >=2.5
diff --git a/src/preprocessing/passes/bv_gauss.cpp b/src/preprocessing/passes/bv_gauss.cpp
index 683716410..b08f69b50 100644
--- a/src/preprocessing/passes/bv_gauss.cpp
+++ b/src/preprocessing/passes/bv_gauss.cpp
@@ -687,8 +687,9 @@ BVGauss::Result BVGauss::gaussElimRewriteForUrem(
return ret;
}
-BVGauss::BVGauss(PreprocessingPassContext* preprocContext)
- : PreprocessingPass(preprocContext, "bv-gauss")
+BVGauss::BVGauss(PreprocessingPassContext* preprocContext,
+ const std::string& name)
+ : PreprocessingPass(preprocContext, name)
{
}
diff --git a/src/preprocessing/passes/bv_gauss.h b/src/preprocessing/passes/bv_gauss.h
index 93d61be9e..7fb23814a 100644
--- a/src/preprocessing/passes/bv_gauss.h
+++ b/src/preprocessing/passes/bv_gauss.h
@@ -30,7 +30,8 @@ namespace passes {
class BVGauss : public PreprocessingPass
{
public:
- BVGauss(PreprocessingPassContext* preprocContext);
+ BVGauss(PreprocessingPassContext* preprocContext,
+ const std::string& name = "bv-gauss");
protected:
/**
diff --git a/src/preprocessing/passes/bv_to_int.cpp b/src/preprocessing/passes/bv_to_int.cpp
index cb78b0897..0e4bc41c0 100644
--- a/src/preprocessing/passes/bv_to_int.cpp
+++ b/src/preprocessing/passes/bv_to_int.cpp
@@ -401,7 +401,28 @@ Node BVToInt::bvToInt(Node n)
d_nm->mkNode(kind::MINUS, mult, multSig);
d_rangeAssertions.insert(
mkRangeConstraint(d_bvToIntCache[current], bvsize));
- d_rangeAssertions.insert(mkRangeConstraint(sigma, bvsize));
+ if (translated_children[0].isConst()
+ || translated_children[1].isConst())
+ {
+ /*
+ * based on equation (23), section 3.2.3 of:
+ * Bozzano et al.
+ * Encoding RTL Constructs for MathSAT: a Preliminary Report.
+ */
+ // this is an optimization when one of the children is constant
+ Node c = translated_children[0].isConst()
+ ? translated_children[0]
+ : translated_children[1];
+ d_rangeAssertions.insert(
+ d_nm->mkNode(kind::LEQ, d_zero, sigma));
+ // the value of sigma is bounded by (c - 1)
+ // where c is the constant multiplicand
+ d_rangeAssertions.insert(d_nm->mkNode(kind::LT, sigma, c));
+ }
+ else
+ {
+ d_rangeAssertions.insert(mkRangeConstraint(sigma, bvsize));
+ }
break;
}
case kind::BITVECTOR_UDIV_TOTAL:
diff --git a/src/preprocessing/passes/synth_rew_rules.cpp b/src/preprocessing/passes/synth_rew_rules.cpp
index 7b8e61359..f1e9e39c5 100644
--- a/src/preprocessing/passes/synth_rew_rules.cpp
+++ b/src/preprocessing/passes/synth_rew_rules.cpp
@@ -169,7 +169,7 @@ PreprocessingPassResult SynthRewRulesPass::applyInternal(
std::stringstream ssv;
if (varCounter < 26)
{
- ssv << String::convertUnsignedIntToChar(varCounter + 32);
+ ssv << static_cast<char>(varCounter + 61);
}
else
{
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index cad3c4640..1178c7299 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -160,6 +160,11 @@ void CvcPrinter::toStream(
toStreamRational(out, n, false);
break;
}
+ case kind::CONST_STRING:
+ {
+ out << '"' << n.getConst<String>().toString() << '"';
+ break;
+ }
case kind::TYPE_CONSTANT:
switch(TypeConstant tc = n.getConst<TypeConstant>()) {
case REAL_TYPE:
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 541827f89..6e4fcb63a 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -202,7 +202,7 @@ void Smt2Printer::toStream(std::ostream& out,
}
case kind::CONST_STRING: {
- std::string s = n.getConst<String>().toString(true);
+ std::string s = n.getConst<String>().toString();
out << '"';
for(size_t i = 0; i < s.size(); ++i) {
char c = s[i];
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 14556708b..f9e3293fa 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -60,9 +60,9 @@ std::string append(const std::string& str, uint64_t num) {
ProofManager::ProofManager(context::Context* context, ProofFormat format)
: d_context(context),
- d_satProof(NULL),
- d_cnfProof(NULL),
- d_theoryProof(NULL),
+ d_satProof(nullptr),
+ d_cnfProof(nullptr),
+ d_theoryProof(nullptr),
d_inputFormulas(),
d_inputCoreFormulas(context),
d_outputCoreFormulas(context),
@@ -73,11 +73,7 @@ ProofManager::ProofManager(context::Context* context, ProofFormat format)
{
}
-ProofManager::~ProofManager() {
- if (d_satProof) delete d_satProof;
- if (d_cnfProof) delete d_cnfProof;
- if (d_theoryProof) delete d_theoryProof;
-}
+ProofManager::~ProofManager() {}
ProofManager* ProofManager::currentPM() {
return smt::currentProofManager();
@@ -89,26 +85,29 @@ const Proof& ProofManager::getProof(SmtEngine* smt)
Assert(currentPM()->d_format == LFSC);
currentPM()->d_fullProof.reset(new LFSCProof(
smt,
- static_cast<CoreSatProof*>(getSatProof()),
+ getSatProof(),
static_cast<LFSCCnfProof*>(getCnfProof()),
static_cast<LFSCTheoryProofEngine*>(getTheoryProofEngine())));
}
return *(currentPM()->d_fullProof);
}
-CoreSatProof* ProofManager::getSatProof() {
+CoreSatProof* ProofManager::getSatProof()
+{
Assert(currentPM()->d_satProof);
- return currentPM()->d_satProof;
+ return currentPM()->d_satProof.get();
}
-CnfProof* ProofManager::getCnfProof() {
+CnfProof* ProofManager::getCnfProof()
+{
Assert(currentPM()->d_cnfProof);
- return currentPM()->d_cnfProof;
+ return currentPM()->d_cnfProof.get();
}
-TheoryProofEngine* ProofManager::getTheoryProofEngine() {
+TheoryProofEngine* ProofManager::getTheoryProofEngine()
+{
Assert(currentPM()->d_theoryProof != NULL);
- return currentPM()->d_theoryProof;
+ return currentPM()->d_theoryProof.get();
}
UFProof* ProofManager::getUfProof() {
@@ -141,43 +140,45 @@ SkolemizationManager* ProofManager::getSkolemizationManager() {
return &(currentPM()->d_skolemizationManager);
}
-void ProofManager::initSatProof(Minisat::Solver* solver) {
- Assert(currentPM()->d_satProof == NULL);
- Assert(currentPM()->d_format == LFSC);
- currentPM()->d_satProof = new CoreSatProof(solver, d_context, "");
+void ProofManager::initSatProof(Minisat::Solver* solver)
+{
+ Assert(d_format == LFSC);
+ // Destroy old instance before initializing new one to avoid issues with
+ // registering stats
+ d_satProof.reset();
+ d_satProof.reset(new CoreSatProof(solver, d_context, ""));
}
void ProofManager::initCnfProof(prop::CnfStream* cnfStream,
- context::Context* ctx) {
- ProofManager* pm = currentPM();
- Assert(pm->d_satProof != NULL);
- Assert(pm->d_cnfProof == NULL);
- Assert(pm->d_format == LFSC);
- CnfProof* cnf = new LFSCCnfProof(cnfStream, ctx, "");
- pm->d_cnfProof = cnf;
+ context::Context* ctx)
+{
+ Assert(d_satProof != nullptr);
+ Assert(d_format == LFSC);
+
+ d_cnfProof.reset(new LFSCCnfProof(cnfStream, ctx, ""));
// true and false have to be setup in a special way
Node true_node = NodeManager::currentNM()->mkConst<bool>(true);
Node false_node = NodeManager::currentNM()->mkConst<bool>(false).notNode();
- pm->d_cnfProof->pushCurrentAssertion(true_node);
- pm->d_cnfProof->pushCurrentDefinition(true_node);
- pm->d_cnfProof->registerConvertedClause(pm->d_satProof->getTrueUnit());
- pm->d_cnfProof->popCurrentAssertion();
- pm->d_cnfProof->popCurrentDefinition();
-
- pm->d_cnfProof->pushCurrentAssertion(false_node);
- pm->d_cnfProof->pushCurrentDefinition(false_node);
- pm->d_cnfProof->registerConvertedClause(pm->d_satProof->getFalseUnit());
- pm->d_cnfProof->popCurrentAssertion();
- pm->d_cnfProof->popCurrentDefinition();
+ d_cnfProof->pushCurrentAssertion(true_node);
+ d_cnfProof->pushCurrentDefinition(true_node);
+ d_cnfProof->registerConvertedClause(d_satProof->getTrueUnit());
+ d_cnfProof->popCurrentAssertion();
+ d_cnfProof->popCurrentDefinition();
+ d_cnfProof->pushCurrentAssertion(false_node);
+ d_cnfProof->pushCurrentDefinition(false_node);
+ d_cnfProof->registerConvertedClause(d_satProof->getFalseUnit());
+ d_cnfProof->popCurrentAssertion();
+ d_cnfProof->popCurrentDefinition();
}
-void ProofManager::initTheoryProofEngine() {
- Assert(currentPM()->d_theoryProof == NULL);
- Assert(currentPM()->d_format == LFSC);
- currentPM()->d_theoryProof = new LFSCTheoryProofEngine();
+void ProofManager::initTheoryProofEngine()
+{
+ Assert(d_theoryProof == NULL);
+ Assert(d_format == LFSC);
+ d_theoryProof.reset(new LFSCTheoryProofEngine());
}
std::string ProofManager::getInputClauseName(ClauseId id,
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index ec845e41d..a59f36858 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -143,9 +143,9 @@ private:
class ProofManager {
context::Context* d_context;
- CoreSatProof* d_satProof;
- CnfProof* d_cnfProof;
- TheoryProofEngine* d_theoryProof;
+ std::unique_ptr<CoreSatProof> d_satProof;
+ std::unique_ptr<CnfProof> d_cnfProof;
+ std::unique_ptr<TheoryProofEngine> d_theoryProof;
// information that will need to be shared across proofs
ExprSet d_inputFormulas;
@@ -179,10 +179,9 @@ public:
static ProofManager* currentPM();
// initialization
- void initSatProof(Minisat::Solver* solver);
- static void initCnfProof(CVC4::prop::CnfStream* cnfStream,
- context::Context* ctx);
- static void initTheoryProofEngine();
+ void initSatProof(Minisat::Solver* solver);
+ void initCnfProof(CVC4::prop::CnfStream* cnfStream, context::Context* ctx);
+ void initTheoryProofEngine();
// getting various proofs
static const Proof& getProof(SmtEngine* smt);
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 80cce599f..f56f6a447 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -662,15 +662,6 @@ Lit Solver::pickBranchLit()
{
Lit nextLit;
-#ifdef CVC4_REPLAY
-
- nextLit = MinisatSatSolver::toMinisatLit(d_proxy->getNextReplayDecision());
-
- if (nextLit != lit_Undef) {
- return nextLit;
- }
-#endif /* CVC4_REPLAY */
-
// Theory requests
nextLit =
MinisatSatSolver::toMinisatLit(d_proxy->getNextTheoryDecisionRequest());
@@ -1547,10 +1538,6 @@ lbool Solver::search(int nof_conflicts)
check_type = CHECK_FINAL;
continue;
}
-
-#ifdef CVC4_REPLAY
- d_proxy->logDecision(MinisatSatSolver::toSatLiteral(next));
-#endif /* CVC4_REPLAY */
}
// Increase decision level and enqueue 'next'
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 19ee29191..89b919109 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -44,13 +44,6 @@
using namespace std;
using namespace CVC4::context;
-
-#ifdef CVC4_REPLAY
-# define CVC4_USE_REPLAY true
-#else /* CVC4_REPLAY */
-# define CVC4_USE_REPLAY false
-#endif /* CVC4_REPLAY */
-
namespace CVC4 {
namespace prop {
@@ -76,9 +69,7 @@ public:
PropEngine::PropEngine(TheoryEngine* te,
Context* satContext,
- UserContext* userContext,
- std::ostream* replayLog,
- ExprStream* replayStream)
+ UserContext* userContext)
: d_inCheckSat(false),
d_theoryEngine(te),
d_context(satContext),
@@ -101,13 +92,8 @@ PropEngine::PropEngine(TheoryEngine* te,
d_cnfStream = new CVC4::prop::TseitinCnfStream(
d_satSolver, d_registrar, userContext, true);
- d_theoryProxy = new TheoryProxy(this,
- d_theoryEngine,
- d_decisionEngine.get(),
- d_context,
- d_cnfStream,
- replayLog,
- replayStream);
+ d_theoryProxy = new TheoryProxy(
+ this, d_theoryEngine, d_decisionEngine.get(), d_context, d_cnfStream);
d_satSolver->initialize(d_context, d_theoryProxy);
d_decisionEngine->setSatSolver(d_satSolver);
@@ -115,6 +101,11 @@ PropEngine::PropEngine(TheoryEngine* te,
PROOF (
ProofManager::currentPM()->initCnfProof(d_cnfStream, userContext);
);
+
+ NodeManager* nm = NodeManager::currentNM();
+ d_cnfStream->convertAndAssert(nm->mkConst(true), false, false, RULE_GIVEN);
+ d_cnfStream->convertAndAssert(
+ nm->mkConst(false).notNode(), false, false, RULE_GIVEN);
}
PropEngine::~PropEngine() {
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index 707244ff5..f1d73fc92 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -24,7 +24,6 @@
#include <sys/time.h>
#include "base/modal_exception.h"
-#include "expr/expr_stream.h"
#include "expr/node.h"
#include "options/options.h"
#include "preprocessing/assertion_pipeline.h"
@@ -62,9 +61,7 @@ class PropEngine
*/
PropEngine(TheoryEngine*,
context::Context* satContext,
- context::UserContext* userContext,
- std::ostream* replayLog,
- ExprStream* replayStream);
+ context::UserContext* userContext);
/**
* Destructor.
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 557dcc413..38c99f551 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -18,7 +18,6 @@
#include "context/context.h"
#include "decision/decision_engine.h"
-#include "expr/expr_stream.h"
#include "options/decision_options.h"
#include "prop/cnf_stream.h"
#include "prop/prop_engine.h"
@@ -37,24 +36,17 @@ TheoryProxy::TheoryProxy(PropEngine* propEngine,
TheoryEngine* theoryEngine,
DecisionEngine* decisionEngine,
context::Context* context,
- CnfStream* cnfStream,
- std::ostream* replayLog,
- ExprStream* replayStream)
+ CnfStream* cnfStream)
: d_propEngine(propEngine),
d_cnfStream(cnfStream),
d_decisionEngine(decisionEngine),
d_theoryEngine(theoryEngine),
- d_replayLog(replayLog),
- d_replayStream(replayStream),
- d_queue(context),
- d_replayedDecisions("prop::theoryproxy::replayedDecisions", 0)
+ d_queue(context)
{
- smtStatisticsRegistry()->registerStat(&d_replayedDecisions);
}
TheoryProxy::~TheoryProxy() {
/* nothing to do for now */
- smtStatisticsRegistry()->unregisterStat(&d_replayedDecisions);
}
void TheoryProxy::variableNotify(SatVariable var) {
@@ -150,29 +142,6 @@ void TheoryProxy::notifyRestart() {
d_theoryEngine->notifyRestart();
}
-SatLiteral TheoryProxy::getNextReplayDecision() {
-#ifdef CVC4_REPLAY
- if(d_replayStream != NULL) {
- Expr e = d_replayStream->nextExpr();
- if(!e.isNull()) { // we get null node when out of decisions to replay
- // convert & return
- ++d_replayedDecisions;
- return d_cnfStream->getLiteral(e);
- }
- }
-#endif /* CVC4_REPLAY */
- return undefSatLiteral;
-}
-
-void TheoryProxy::logDecision(SatLiteral lit) {
-#ifdef CVC4_REPLAY
- if(d_replayLog != NULL) {
- Assert(lit != undefSatLiteral) << "logging an `undef' decision ?!";
- (*d_replayLog) << d_cnfStream->getNode(lit) << std::endl;
- }
-#endif /* CVC4_REPLAY */
-}
-
void TheoryProxy::spendResource(ResourceManager::Resource r)
{
d_theoryEngine->spendResource(r);
diff --git a/src/prop/theory_proxy.h b/src/prop/theory_proxy.h
index 0d76b473f..089d2082d 100644
--- a/src/prop/theory_proxy.h
+++ b/src/prop/theory_proxy.h
@@ -27,7 +27,6 @@
#include <unordered_set>
#include "context/cdqueue.h"
-#include "expr/expr_stream.h"
#include "expr/node.h"
#include "prop/sat_solver.h"
#include "theory/theory.h"
@@ -54,9 +53,7 @@ class TheoryProxy
TheoryEngine* theoryEngine,
DecisionEngine* decisionEngine,
context::Context* context,
- CnfStream* cnfStream,
- std::ostream* replayLog,
- ExprStream* replayStream);
+ CnfStream* cnfStream);
~TheoryProxy();
@@ -83,10 +80,6 @@ class TheoryProxy
void notifyRestart();
- SatLiteral getNextReplayDecision();
-
- void logDecision(SatLiteral lit);
-
void spendResource(ResourceManager::Resource r);
bool isDecisionEngineDone();
@@ -111,12 +104,6 @@ class TheoryProxy
/** The theory engine we are using. */
TheoryEngine* d_theoryEngine;
- /** Stream on which to log replay events. */
- std::ostream* d_replayLog;
-
- /** Stream for replaying decisions. */
- ExprStream* d_replayStream;
-
/** Queue of asserted facts */
context::CDQueue<TNode> d_queue;
@@ -126,11 +113,6 @@ class TheoryProxy
*/
std::unordered_set<Node, NodeHashFunction> d_shared;
- /**
- * Statistic: the number of replayed decisions (via --replay).
- */
- IntStat d_replayedDecisions;
-
}; /* class SatSolver */
}/* CVC4::prop namespace */
diff --git a/src/smt/command.cpp b/src/smt/command.cpp
index 79cc465ac..20f2dcff9 100644
--- a/src/smt/command.cpp
+++ b/src/smt/command.cpp
@@ -513,7 +513,7 @@ void QueryCommand::invoke(SmtEngine* smtEngine)
{
try
{
- d_result = smtEngine->query(d_expr);
+ d_result = smtEngine->checkEntailed(d_expr);
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
diff --git a/src/smt/managed_ostreams.cpp b/src/smt/managed_ostreams.cpp
index a73ec44f4..7615325b7 100644
--- a/src/smt/managed_ostreams.cpp
+++ b/src/smt/managed_ostreams.cpp
@@ -163,31 +163,4 @@ void ManagedDiagnosticOutputChannel::addSpecialCases(OstreamOpener* opener)
opener->addSpecialCase("stderr", &std::cerr);
}
-
-ManagedReplayLogOstream::ManagedReplayLogOstream() : d_replayLog(NULL) {}
-ManagedReplayLogOstream::~ManagedReplayLogOstream(){
- if(d_replayLog != NULL) {
- (*d_replayLog) << std::flush;
- }
-}
-
-std::string ManagedReplayLogOstream::defaultSource() const {
- return options::replayLogFilename();
-}
-
-void ManagedReplayLogOstream::initialize(std::ostream* outStream) {
- if(outStream != NULL){
- *outStream << language::SetLanguage(options::outputLanguage())
- << expr::ExprSetDepth(-1);
- }
- /* Do this regardless of managing the memory. */
- d_replayLog = outStream;
-}
-
-/** Adds special cases to an ostreamopener. */
-void ManagedReplayLogOstream::addSpecialCases(OstreamOpener* opener) const {
- opener->addSpecialCase("-", &std::cout);
-}
-
-
}/* CVC4 namespace */
diff --git a/src/smt/managed_ostreams.h b/src/smt/managed_ostreams.h
index f495f8e72..bc12bbe39 100644
--- a/src/smt/managed_ostreams.h
+++ b/src/smt/managed_ostreams.h
@@ -156,27 +156,6 @@ class ManagedDiagnosticOutputChannel : public ManagedOstream {
void addSpecialCases(OstreamOpener* opener) const override;
};/* class ManagedRegularOutputChannel */
-/** This controls the memory associated with replay-log. */
-class ManagedReplayLogOstream : public ManagedOstream {
- public:
- ManagedReplayLogOstream();
- ~ManagedReplayLogOstream();
-
- std::ostream* getReplayLog() const { return d_replayLog; }
- const char* getName() const override { return "replay-log"; }
- std::string defaultSource() const override;
-
- protected:
- /** Initializes an output stream. Not necessarily managed. */
- void initialize(std::ostream* outStream) override;
-
- /** Adds special cases to an ostreamopener. */
- void addSpecialCases(OstreamOpener* opener) const override;
-
- private:
- std::ostream* d_replayLog;
-};/* class ManagedRegularOutputChannel */
-
}/* CVC4 namespace */
#endif /* CVC4__MANAGED_OSTREAMS_H */
diff --git a/src/smt/set_defaults.cpp b/src/smt/set_defaults.cpp
new file mode 100644
index 000000000..e0493b180
--- /dev/null
+++ b/src/smt/set_defaults.cpp
@@ -0,0 +1,1353 @@
+/********************* */
+/*! \file set_defaults.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of setting default options.
+ **/
+
+#include "smt/set_defaults.h"
+
+#include "base/output.h"
+#include "options/arith_options.h"
+#include "options/arrays_options.h"
+#include "options/base_options.h"
+#include "options/booleans_options.h"
+#include "options/bv_options.h"
+#include "options/datatypes_options.h"
+#include "options/decision_options.h"
+#include "options/language.h"
+#include "options/main_options.h"
+#include "options/open_ostream.h"
+#include "options/option_exception.h"
+#include "options/printer_options.h"
+#include "options/proof_options.h"
+#include "options/prop_options.h"
+#include "options/quantifiers_options.h"
+#include "options/sep_options.h"
+#include "options/set_language.h"
+#include "options/smt_options.h"
+#include "options/strings_options.h"
+#include "options/theory_options.h"
+#include "options/uf_options.h"
+#include "theory/theory.h"
+
+using namespace CVC4::theory;
+
+namespace CVC4 {
+namespace smt {
+
+void setDefaults(SmtEngine& smte, LogicInfo& logic)
+{
+ // Language-based defaults
+ if (!options::bitvectorDivByZeroConst.wasSetByUser())
+ {
+ // Bitvector-divide-by-zero changed semantics in SMT LIB 2.6, thus we
+ // set this option if the input format is SMT LIB 2.6. We also set this
+ // option if we are sygus, since we assume SMT LIB 2.6 semantics for sygus.
+ options::bitvectorDivByZeroConst.set(
+ language::isInputLang_smt2_6(options::inputLanguage())
+ || language::isInputLangSygus(options::inputLanguage()));
+ }
+ bool is_sygus = language::isInputLangSygus(options::inputLanguage());
+
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ {
+ if (options::produceModels()
+ && (logic.isTheoryEnabled(THEORY_ARRAYS)
+ || logic.isTheoryEnabled(THEORY_UF)))
+ {
+ if (options::bitblastMode.wasSetByUser()
+ || options::produceModels.wasSetByUser())
+ {
+ throw OptionException(std::string(
+ "Eager bit-blasting currently does not support model generation "
+ "for the combination of bit-vectors with arrays or uinterpreted "
+ "functions. Try --bitblast=lazy"));
+ }
+ Notice() << "SmtEngine: setting bit-blast mode to lazy to support model"
+ << "generation" << std::endl;
+ smte.setOption("bitblastMode", SExpr("lazy"));
+ }
+ else if (!options::incrementalSolving())
+ {
+ options::ackermann.set(true);
+ }
+
+ if (options::incrementalSolving() && !logic.isPure(THEORY_BV))
+ {
+ throw OptionException(
+ "Incremental eager bit-blasting is currently "
+ "only supported for QF_BV. Try --bitblast=lazy.");
+ }
+ }
+
+ if (options::solveIntAsBV() > 0)
+ {
+ logic = logic.getUnlockedCopy();
+ logic.enableTheory(THEORY_BV);
+ logic.lock();
+ }
+
+ if (options::solveBVAsInt() > 0)
+ {
+ if (logic.isTheoryEnabled(THEORY_BV))
+ {
+ logic = logic.getUnlockedCopy();
+ logic.enableTheory(THEORY_ARITH);
+ logic.arithNonLinear();
+ logic.lock();
+ }
+ }
+
+ // set options about ackermannization
+ if (options::ackermann() && options::produceModels()
+ && (logic.isTheoryEnabled(THEORY_ARRAYS)
+ || logic.isTheoryEnabled(THEORY_UF)))
+ {
+ if (options::produceModels.wasSetByUser())
+ {
+ throw OptionException(std::string(
+ "Ackermannization currently does not support model generation."));
+ }
+ Notice() << "SmtEngine: turn off ackermannization to support model"
+ << "generation" << std::endl;
+ options::ackermann.set(false);
+ }
+
+ if (options::ackermann())
+ {
+ if (options::incrementalSolving())
+ {
+ throw OptionException(
+ "Incremental Ackermannization is currently not supported.");
+ }
+
+ if (logic.isQuantified())
+ {
+ throw LogicException("Cannot use Ackermannization on quantified formula");
+ }
+
+ if (logic.isTheoryEnabled(THEORY_UF))
+ {
+ logic = logic.getUnlockedCopy();
+ logic.disableTheory(THEORY_UF);
+ logic.lock();
+ }
+ if (logic.isTheoryEnabled(THEORY_ARRAYS))
+ {
+ logic = logic.getUnlockedCopy();
+ logic.disableTheory(THEORY_ARRAYS);
+ logic.lock();
+ }
+ }
+
+ // Set default options associated with strings-exp. We also set these options
+ // if we are using eager string preprocessing, which may introduce quantified
+ // formulas at preprocess time.
+ if (options::stringExp() || !options::stringLazyPreproc())
+ {
+ // We require quantifiers since extended functions reduce using them.
+ if (!logic.isQuantified())
+ {
+ logic = logic.getUnlockedCopy();
+ logic.enableQuantifiers();
+ logic.lock();
+ Trace("smt") << "turning on quantifier logic, for strings-exp"
+ << std::endl;
+ }
+ // We require bounded quantifier handling.
+ if (!options::fmfBound.wasSetByUser())
+ {
+ options::fmfBound.set(true);
+ Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
+ }
+ // Turn off E-matching, since some bounded quantifiers introduced by strings
+ // (e.g. for replaceall) admit matching loops.
+ if (!options::eMatching.wasSetByUser())
+ {
+ options::eMatching.set(false);
+ Trace("smt") << "turning off E-matching, for strings-exp" << std::endl;
+ }
+ // Do not eliminate extended arithmetic symbols from quantified formulas,
+ // since some strategies, e.g. --re-elim-agg, introduce them.
+ if (!options::elimExtArithQuant.wasSetByUser())
+ {
+ options::elimExtArithQuant.set(false);
+ Trace("smt") << "turning off elim-ext-arith-quant, for strings-exp"
+ << std::endl;
+ }
+ }
+
+ // sygus inference may require datatypes
+ if (!smte.isInternalSubsolver())
+ {
+ if (options::produceAbducts() || options::sygusInference()
+ || options::sygusRewSynthInput())
+ {
+ // since we are trying to recast as sygus, we assume the input is sygus
+ is_sygus = true;
+ }
+ }
+
+ // We now know whether the input is sygus. Update the logic to incorporate
+ // the theories we need internally for handling sygus problems.
+ if (is_sygus)
+ {
+ logic = logic.getUnlockedCopy();
+ logic.enableSygus();
+ logic.lock();
+ }
+
+ // sygus core connective requires unsat cores
+ if (options::sygusCoreConnective())
+ {
+ options::unsatCores.set(true);
+ }
+
+ if ((options::checkModels() || options::checkSynthSol()
+ || options::produceAbducts()
+ || options::modelCoresMode() != options::ModelCoresMode::NONE
+ || options::blockModelsMode() != options::BlockModelsMode::NONE)
+ && !options::produceAssertions())
+ {
+ Notice() << "SmtEngine: turning on produce-assertions to support "
+ << "option requiring assertions." << std::endl;
+ smte.setOption("produce-assertions", SExpr("true"));
+ }
+
+ // Disable options incompatible with incremental solving, unsat cores, and
+ // proofs or output an error if enabled explicitly
+ if (options::incrementalSolving() || options::unsatCores()
+ || options::proof())
+ {
+ if (options::unconstrainedSimp())
+ {
+ if (options::unconstrainedSimp.wasSetByUser())
+ {
+ throw OptionException(
+ "unconstrained simplification not supported with unsat "
+ "cores/proofs/incremental solving");
+ }
+ Notice() << "SmtEngine: turning off unconstrained simplification to "
+ "support unsat cores/proofs/incremental solving"
+ << std::endl;
+ options::unconstrainedSimp.set(false);
+ }
+ }
+ else
+ {
+ // Turn on unconstrained simplification for QF_AUFBV
+ if (!options::unconstrainedSimp.wasSetByUser())
+ {
+ bool uncSimp = !logic.isQuantified() && !options::produceModels()
+ && !options::produceAssignments()
+ && !options::checkModels()
+ && (logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_BV));
+ Trace("smt") << "setting unconstrained simplification to " << uncSimp
+ << std::endl;
+ options::unconstrainedSimp.set(uncSimp);
+ }
+ }
+
+ if (options::incrementalSolving() || options::proof())
+ {
+ if (options::sygusInference())
+ {
+ if (options::sygusInference.wasSetByUser())
+ {
+ throw OptionException(
+ "sygus inference not supported with proofs/incremental solving");
+ }
+ Notice() << "SmtEngine: turning off sygus inference to support "
+ "proofs/incremental solving"
+ << std::endl;
+ options::sygusInference.set(false);
+ }
+ }
+
+ // Disable options incompatible with unsat cores and proofs or output an
+ // error if enabled explicitly
+ if (options::unsatCores() || options::proof())
+ {
+ if (options::simplificationMode() != options::SimplificationMode::NONE)
+ {
+ if (options::simplificationMode.wasSetByUser())
+ {
+ throw OptionException(
+ "simplification not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off simplification to support unsat "
+ "cores/proofs"
+ << std::endl;
+ options::simplificationMode.set(options::SimplificationMode::NONE);
+ }
+
+ if (options::pbRewrites())
+ {
+ if (options::pbRewrites.wasSetByUser())
+ {
+ throw OptionException(
+ "pseudoboolean rewrites not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off pseudoboolean rewrites to support "
+ "unsat cores/proofs"
+ << std::endl;
+ smte.setOption("pb-rewrites", false);
+ }
+
+ if (options::sortInference())
+ {
+ if (options::sortInference.wasSetByUser())
+ {
+ throw OptionException(
+ "sort inference not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off sort inference to support unsat "
+ "cores/proofs"
+ << std::endl;
+ options::sortInference.set(false);
+ }
+
+ if (options::preSkolemQuant())
+ {
+ if (options::preSkolemQuant.wasSetByUser())
+ {
+ throw OptionException(
+ "pre-skolemization not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off pre-skolemization to support unsat "
+ "cores/proofs"
+ << std::endl;
+ options::preSkolemQuant.set(false);
+ }
+
+ if (options::solveBVAsInt() > 0)
+ {
+ /**
+ * Operations on 1 bits are better handled as Boolean operations
+ * than as integer operations.
+ * Therefore, we enable bv-to-bool, which runs before
+ * the translation to integers.
+ */
+ options::bitvectorToBool.set(true);
+ }
+
+ if (options::bitvectorToBool())
+ {
+ if (options::bitvectorToBool.wasSetByUser())
+ {
+ throw OptionException(
+ "bv-to-bool not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat "
+ "cores/proofs"
+ << std::endl;
+ options::bitvectorToBool.set(false);
+ }
+
+ if (options::boolToBitvector() != options::BoolToBVMode::OFF)
+ {
+ if (options::boolToBitvector.wasSetByUser())
+ {
+ throw OptionException(
+ "bool-to-bv != off not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off bool-to-bv to support unsat "
+ "cores/proofs"
+ << std::endl;
+ smte.setOption("boolToBitvector", SExpr("off"));
+ }
+
+ if (options::bvIntroducePow2())
+ {
+ if (options::bvIntroducePow2.wasSetByUser())
+ {
+ throw OptionException(
+ "bv-intro-pow2 not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off bv-intro-pow2 to support "
+ "unsat-cores/proofs"
+ << std::endl;
+ smte.setOption("bv-intro-pow2", false);
+ }
+
+ if (options::repeatSimp())
+ {
+ if (options::repeatSimp.wasSetByUser())
+ {
+ throw OptionException(
+ "repeat-simp not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off repeat-simp to support unsat "
+ "cores/proofs"
+ << std::endl;
+ smte.setOption("repeat-simp", false);
+ }
+
+ if (options::globalNegate())
+ {
+ if (options::globalNegate.wasSetByUser())
+ {
+ throw OptionException(
+ "global-negate not supported with unsat cores/proofs");
+ }
+ Notice() << "SmtEngine: turning off global-negate to support unsat "
+ "cores/proofs"
+ << std::endl;
+ smte.setOption("global-negate", false);
+ }
+
+ if (options::bitvectorAig())
+ {
+ throw OptionException(
+ "bitblast-aig not supported with unsat cores/proofs");
+ }
+ }
+ else
+ {
+ // by default, nonclausal simplification is off for QF_SAT
+ if (!options::simplificationMode.wasSetByUser())
+ {
+ bool qf_sat = logic.isPure(THEORY_BOOL) && !logic.isQuantified();
+ Trace("smt") << "setting simplification mode to <"
+ << logic.getLogicString() << "> " << (!qf_sat) << std::endl;
+ // simplification=none works better for SMT LIB benchmarks with
+ // quantifiers, not others options::simplificationMode.set(qf_sat ||
+ // quantifiers ? options::SimplificationMode::NONE :
+ // options::SimplificationMode::BATCH);
+ options::simplificationMode.set(qf_sat
+ ? options::SimplificationMode::NONE
+ : options::SimplificationMode::BATCH);
+ }
+ }
+
+ if (options::cbqiBv() && logic.isQuantified())
+ {
+ if (options::boolToBitvector() != options::BoolToBVMode::OFF)
+ {
+ if (options::boolToBitvector.wasSetByUser())
+ {
+ throw OptionException(
+ "bool-to-bv != off not supported with CBQI BV for quantified "
+ "logics");
+ }
+ Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
+ << std::endl;
+ smte.setOption("boolToBitvector", SExpr("off"));
+ }
+ }
+
+ // cases where we need produce models
+ if (!options::produceModels()
+ && (options::produceAssignments() || options::sygusRewSynthCheck()
+ || is_sygus))
+ {
+ Notice() << "SmtEngine: turning on produce-models" << std::endl;
+ smte.setOption("produce-models", SExpr("true"));
+ }
+
+ // Set the options for the theoryOf
+ if (!options::theoryOfMode.wasSetByUser())
+ {
+ if (logic.isSharingEnabled() && !logic.isTheoryEnabled(THEORY_BV)
+ && !logic.isTheoryEnabled(THEORY_STRINGS)
+ && !logic.isTheoryEnabled(THEORY_SETS))
+ {
+ Trace("smt") << "setting theoryof-mode to term-based" << std::endl;
+ options::theoryOfMode.set(options::TheoryOfMode::THEORY_OF_TERM_BASED);
+ }
+ }
+
+ // strings require LIA, UF; widen the logic
+ if (logic.isTheoryEnabled(THEORY_STRINGS))
+ {
+ LogicInfo log(logic.getUnlockedCopy());
+ // Strings requires arith for length constraints, and also UF
+ if (!logic.isTheoryEnabled(THEORY_UF))
+ {
+ Trace("smt") << "because strings are enabled, also enabling UF"
+ << std::endl;
+ log.enableTheory(THEORY_UF);
+ }
+ if (!logic.isTheoryEnabled(THEORY_ARITH) || logic.isDifferenceLogic()
+ || !logic.areIntegersUsed())
+ {
+ Trace("smt") << "because strings are enabled, also enabling linear "
+ "integer arithmetic"
+ << std::endl;
+ log.enableTheory(THEORY_ARITH);
+ log.enableIntegers();
+ log.arithOnlyLinear();
+ }
+ logic = log;
+ logic.lock();
+ }
+ if (logic.isTheoryEnabled(THEORY_ARRAYS)
+ || logic.isTheoryEnabled(THEORY_DATATYPES)
+ || logic.isTheoryEnabled(THEORY_SETS))
+ {
+ if (!logic.isTheoryEnabled(THEORY_UF))
+ {
+ LogicInfo log(logic.getUnlockedCopy());
+ Trace("smt") << "because a theory that permits Boolean terms is enabled, "
+ "also enabling UF"
+ << std::endl;
+ log.enableTheory(THEORY_UF);
+ logic = log;
+ logic.lock();
+ }
+ }
+
+ // by default, symmetry breaker is on only for non-incremental QF_UF
+ if (!options::ufSymmetryBreaker.wasSetByUser())
+ {
+ bool qf_uf_noinc = logic.isPure(THEORY_UF) && !logic.isQuantified()
+ && !options::incrementalSolving() && !options::proof()
+ && !options::unsatCores();
+ Trace("smt") << "setting uf symmetry breaker to " << qf_uf_noinc
+ << std::endl;
+ options::ufSymmetryBreaker.set(qf_uf_noinc);
+ }
+
+ // If in arrays, set the UF handler to arrays
+ if (logic.isTheoryEnabled(THEORY_ARRAYS)
+ && (!logic.isQuantified()
+ || (logic.isQuantified() && !logic.isTheoryEnabled(THEORY_UF))))
+ {
+ Theory::setUninterpretedSortOwner(THEORY_ARRAYS);
+ }
+ else
+ {
+ Theory::setUninterpretedSortOwner(THEORY_UF);
+ }
+
+ if (!options::simplifyWithCareEnabled.wasSetByUser())
+ {
+ bool qf_aufbv =
+ !logic.isQuantified() && logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_UF) && logic.isTheoryEnabled(THEORY_BV);
+
+ bool withCare = qf_aufbv;
+ Trace("smt") << "setting ite simplify with care to " << withCare
+ << std::endl;
+ options::simplifyWithCareEnabled.set(withCare);
+ }
+ // Turn off array eager index splitting for QF_AUFLIA
+ if (!options::arraysEagerIndexSplitting.wasSetByUser())
+ {
+ if (not logic.isQuantified() && logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_UF)
+ && logic.isTheoryEnabled(THEORY_ARITH))
+ {
+ Trace("smt") << "setting array eager index splitting to false"
+ << std::endl;
+ options::arraysEagerIndexSplitting.set(false);
+ }
+ }
+ // Turn on multiple-pass non-clausal simplification for QF_AUFBV
+ if (!options::repeatSimp.wasSetByUser())
+ {
+ bool repeatSimp = !logic.isQuantified()
+ && (logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_UF)
+ && logic.isTheoryEnabled(THEORY_BV))
+ && !options::unsatCores();
+ Trace("smt") << "setting repeat simplification to " << repeatSimp
+ << std::endl;
+ options::repeatSimp.set(repeatSimp);
+ }
+
+ if (options::boolToBitvector() == options::BoolToBVMode::ALL
+ && !logic.isTheoryEnabled(THEORY_BV))
+ {
+ if (options::boolToBitvector.wasSetByUser())
+ {
+ throw OptionException(
+ "bool-to-bv=all not supported for non-bitvector logics.");
+ }
+ Notice() << "SmtEngine: turning off bool-to-bv for non-bv logic: "
+ << logic.getLogicString() << std::endl;
+ smte.setOption("boolToBitvector", SExpr("off"));
+ }
+
+ if (!options::bvEagerExplanations.wasSetByUser()
+ && logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_BV))
+ {
+ Trace("smt") << "enabling eager bit-vector explanations " << std::endl;
+ options::bvEagerExplanations.set(true);
+ }
+
+ // Turn on arith rewrite equalities only for pure arithmetic
+ if (!options::arithRewriteEq.wasSetByUser())
+ {
+ bool arithRewriteEq =
+ logic.isPure(THEORY_ARITH) && logic.isLinear() && !logic.isQuantified();
+ Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq
+ << std::endl;
+ options::arithRewriteEq.set(arithRewriteEq);
+ }
+ if (!options::arithHeuristicPivots.wasSetByUser())
+ {
+ int16_t heuristicPivots = 5;
+ if (logic.isPure(THEORY_ARITH) && !logic.isQuantified())
+ {
+ if (logic.isDifferenceLogic())
+ {
+ heuristicPivots = -1;
+ }
+ else if (!logic.areIntegersUsed())
+ {
+ heuristicPivots = 0;
+ }
+ }
+ Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots
+ << std::endl;
+ options::arithHeuristicPivots.set(heuristicPivots);
+ }
+ if (!options::arithPivotThreshold.wasSetByUser())
+ {
+ uint16_t pivotThreshold = 2;
+ if (logic.isPure(THEORY_ARITH) && !logic.isQuantified())
+ {
+ if (logic.isDifferenceLogic())
+ {
+ pivotThreshold = 16;
+ }
+ }
+ Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold
+ << std::endl;
+ options::arithPivotThreshold.set(pivotThreshold);
+ }
+ if (!options::arithStandardCheckVarOrderPivots.wasSetByUser())
+ {
+ int16_t varOrderPivots = -1;
+ if (logic.isPure(THEORY_ARITH) && !logic.isQuantified())
+ {
+ varOrderPivots = 200;
+ }
+ Trace("smt") << "setting arithStandardCheckVarOrderPivots "
+ << varOrderPivots << std::endl;
+ options::arithStandardCheckVarOrderPivots.set(varOrderPivots);
+ }
+ if (logic.isPure(THEORY_ARITH) && !logic.areRealsUsed())
+ {
+ if (!options::nlExtTangentPlanesInterleave.wasSetByUser())
+ {
+ Trace("smt") << "setting nlExtTangentPlanesInterleave to true"
+ << std::endl;
+ options::nlExtTangentPlanesInterleave.set(true);
+ }
+ }
+
+ // Set decision mode based on logic (if not set by user)
+ if (!options::decisionMode.wasSetByUser())
+ {
+ options::DecisionMode decMode =
+ // sygus uses internal
+ is_sygus ? options::DecisionMode::INTERNAL :
+ // ALL
+ logic.hasEverything()
+ ? options::DecisionMode::JUSTIFICATION
+ : ( // QF_BV
+ (not logic.isQuantified() && logic.isPure(THEORY_BV)) ||
+ // QF_AUFBV or QF_ABV or QF_UFBV
+ (not logic.isQuantified()
+ && (logic.isTheoryEnabled(THEORY_ARRAYS)
+ || logic.isTheoryEnabled(THEORY_UF))
+ && logic.isTheoryEnabled(THEORY_BV))
+ ||
+ // QF_AUFLIA (and may be ends up enabling
+ // QF_AUFLRA?)
+ (not logic.isQuantified()
+ && logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_UF)
+ && logic.isTheoryEnabled(THEORY_ARITH))
+ ||
+ // QF_LRA
+ (not logic.isQuantified()
+ && logic.isPure(THEORY_ARITH) && logic.isLinear()
+ && !logic.isDifferenceLogic()
+ && !logic.areIntegersUsed())
+ ||
+ // Quantifiers
+ logic.isQuantified() ||
+ // Strings
+ logic.isTheoryEnabled(THEORY_STRINGS)
+ ? options::DecisionMode::JUSTIFICATION
+ : options::DecisionMode::INTERNAL);
+
+ bool stoponly =
+ // ALL
+ logic.hasEverything() || logic.isTheoryEnabled(THEORY_STRINGS)
+ ? false
+ : ( // QF_AUFLIA
+ (not logic.isQuantified()
+ && logic.isTheoryEnabled(THEORY_ARRAYS)
+ && logic.isTheoryEnabled(THEORY_UF)
+ && logic.isTheoryEnabled(THEORY_ARITH))
+ ||
+ // QF_LRA
+ (not logic.isQuantified()
+ && logic.isPure(THEORY_ARITH) && logic.isLinear()
+ && !logic.isDifferenceLogic()
+ && !logic.areIntegersUsed())
+ ? true
+ : false);
+
+ Trace("smt") << "setting decision mode to " << decMode << std::endl;
+ options::decisionMode.set(decMode);
+ options::decisionStopOnly.set(stoponly);
+ }
+ if (options::incrementalSolving())
+ {
+ // disable modes not supported by incremental
+ options::sortInference.set(false);
+ options::ufssFairnessMonotone.set(false);
+ options::quantEpr.set(false);
+ options::globalNegate.set(false);
+ }
+ if (logic.hasCardinalityConstraints())
+ {
+ // must have finite model finding on
+ options::finiteModelFind.set(true);
+ }
+
+ // if it contains a theory with non-termination, do not strictly enforce that
+ // quantifiers and theory combination must be interleaved
+ if (logic.isTheoryEnabled(THEORY_STRINGS)
+ || (logic.isTheoryEnabled(THEORY_ARITH) && !logic.isLinear()))
+ {
+ if (!options::instWhenStrictInterleave.wasSetByUser())
+ {
+ options::instWhenStrictInterleave.set(false);
+ }
+ }
+
+ if (options::instMaxLevel() != -1)
+ {
+ Notice() << "SmtEngine: turning off cbqi to support instMaxLevel"
+ << std::endl;
+ options::cbqi.set(false);
+ }
+ // Do we need to track instantiations?
+ // Needed for sygus due to single invocation techniques.
+ if (options::cbqiNestedQE()
+ || (options::proof() && !options::trackInstLemmas.wasSetByUser())
+ || is_sygus)
+ {
+ options::trackInstLemmas.set(true);
+ }
+
+ if ((options::fmfBoundLazy.wasSetByUser() && options::fmfBoundLazy())
+ || (options::fmfBoundInt.wasSetByUser() && options::fmfBoundInt()))
+ {
+ options::fmfBound.set(true);
+ }
+ // now have determined whether fmfBoundInt is on/off
+ // apply fmfBoundInt options
+ if (options::fmfBound())
+ {
+ if (!options::mbqiMode.wasSetByUser()
+ || (options::mbqiMode() != options::MbqiMode::NONE
+ && options::mbqiMode() != options::MbqiMode::FMC))
+ {
+ // if bounded integers are set, use no MBQI by default
+ options::mbqiMode.set(options::MbqiMode::NONE);
+ }
+ if (!options::prenexQuant.wasSetByUser())
+ {
+ options::prenexQuant.set(options::PrenexQuantMode::NONE);
+ }
+ }
+ if (options::ufHo())
+ {
+ // if higher-order, then current variants of model-based instantiation
+ // cannot be used
+ if (options::mbqiMode() != options::MbqiMode::NONE)
+ {
+ options::mbqiMode.set(options::MbqiMode::NONE);
+ }
+ if (!options::hoElimStoreAx.wasSetByUser())
+ {
+ // by default, use store axioms only if --ho-elim is set
+ options::hoElimStoreAx.set(options::hoElim());
+ }
+ }
+ if (options::fmfFunWellDefinedRelevant())
+ {
+ if (!options::fmfFunWellDefined.wasSetByUser())
+ {
+ options::fmfFunWellDefined.set(true);
+ }
+ }
+ if (options::fmfFunWellDefined())
+ {
+ if (!options::finiteModelFind.wasSetByUser())
+ {
+ options::finiteModelFind.set(true);
+ }
+ }
+ // EPR
+ if (options::quantEpr())
+ {
+ if (!options::preSkolemQuant.wasSetByUser())
+ {
+ options::preSkolemQuant.set(true);
+ }
+ }
+
+ // now, have determined whether finite model find is on/off
+ // apply finite model finding options
+ if (options::finiteModelFind())
+ {
+ // apply conservative quantifiers splitting
+ if (!options::quantDynamicSplit.wasSetByUser())
+ {
+ options::quantDynamicSplit.set(options::QuantDSplitMode::DEFAULT);
+ }
+ // do not eliminate extended arithmetic symbols from quantified formulas
+ if (!options::elimExtArithQuant.wasSetByUser())
+ {
+ options::elimExtArithQuant.set(false);
+ }
+ if (!options::eMatching.wasSetByUser())
+ {
+ options::eMatching.set(options::fmfInstEngine());
+ }
+ if (!options::instWhenMode.wasSetByUser())
+ {
+ // instantiate only on last call
+ if (options::eMatching())
+ {
+ options::instWhenMode.set(options::InstWhenMode::LAST_CALL);
+ }
+ }
+ }
+
+ // apply sygus options
+ // if we are attempting to rewrite everything to SyGuS, use sygus()
+ if (is_sygus)
+ {
+ if (!options::sygus())
+ {
+ Trace("smt") << "turning on sygus" << std::endl;
+ }
+ options::sygus.set(true);
+ // must use Ferrante/Rackoff for real arithmetic
+ if (!options::cbqiMidpoint.wasSetByUser())
+ {
+ options::cbqiMidpoint.set(true);
+ }
+ if (options::sygusRepairConst())
+ {
+ if (!options::cbqi.wasSetByUser())
+ {
+ options::cbqi.set(true);
+ }
+ }
+ if (options::sygusInference())
+ {
+ // optimization: apply preskolemization, makes it succeed more often
+ if (!options::preSkolemQuant.wasSetByUser())
+ {
+ options::preSkolemQuant.set(true);
+ }
+ if (!options::preSkolemQuantNested.wasSetByUser())
+ {
+ options::preSkolemQuantNested.set(true);
+ }
+ }
+ // counterexample-guided instantiation for sygus
+ if (!options::cegqiSingleInvMode.wasSetByUser())
+ {
+ options::cegqiSingleInvMode.set(options::CegqiSingleInvMode::USE);
+ }
+ if (!options::quantConflictFind.wasSetByUser())
+ {
+ options::quantConflictFind.set(false);
+ }
+ if (!options::instNoEntail.wasSetByUser())
+ {
+ options::instNoEntail.set(false);
+ }
+ if (!options::cbqiFullEffort.wasSetByUser())
+ {
+ // should use full effort cbqi for single invocation and repair const
+ options::cbqiFullEffort.set(true);
+ }
+ if (options::sygusRew())
+ {
+ options::sygusRewSynth.set(true);
+ options::sygusRewVerify.set(true);
+ }
+ if (options::sygusRewSynthInput())
+ {
+ // If we are using synthesis rewrite rules from input, we use
+ // sygusRewSynth after preprocessing. See passes/synth_rew_rules.h for
+ // details on this technique.
+ options::sygusRewSynth.set(true);
+ // we should not use the extended rewriter, since we are interested
+ // in rewrites that are not in the main rewriter
+ if (!options::sygusExtRew.wasSetByUser())
+ {
+ options::sygusExtRew.set(false);
+ }
+ }
+ // Whether we must use "basic" sygus algorithms. A non-basic sygus algorithm
+ // is one that is specialized for returning a single solution. Non-basic
+ // sygus algorithms currently include the PBE solver, UNIF+PI, static
+ // template inference for invariant synthesis, and single invocation
+ // techniques.
+ bool reqBasicSygus = false;
+ if (options::produceAbducts())
+ {
+ // if doing abduction, we should filter strong solutions
+ if (!options::sygusFilterSolMode.wasSetByUser())
+ {
+ options::sygusFilterSolMode.set(options::SygusFilterSolMode::STRONG);
+ }
+ // we must use basic sygus algorithms, since e.g. we require checking
+ // a sygus side condition for consistency with axioms.
+ reqBasicSygus = true;
+ }
+ if (options::sygusRewSynth() || options::sygusRewVerify()
+ || options::sygusQueryGen())
+ {
+ // rewrite rule synthesis implies that sygus stream must be true
+ options::sygusStream.set(true);
+ }
+ if (options::sygusStream() || options::incrementalSolving())
+ {
+ // Streaming and incremental mode are incompatible with techniques that
+ // focus the search towards finding a single solution.
+ reqBasicSygus = true;
+ }
+ // Now, disable options for non-basic sygus algorithms, if necessary.
+ if (reqBasicSygus)
+ {
+ if (!options::sygusUnifPbe.wasSetByUser())
+ {
+ options::sygusUnifPbe.set(false);
+ }
+ if (options::sygusUnifPi.wasSetByUser())
+ {
+ options::sygusUnifPi.set(options::SygusUnifPiMode::NONE);
+ }
+ if (!options::sygusInvTemplMode.wasSetByUser())
+ {
+ options::sygusInvTemplMode.set(options::SygusInvTemplMode::NONE);
+ }
+ if (!options::cegqiSingleInvMode.wasSetByUser())
+ {
+ options::cegqiSingleInvMode.set(options::CegqiSingleInvMode::NONE);
+ }
+ }
+ // do not allow partial functions
+ if (!options::bitvectorDivByZeroConst())
+ {
+ if (options::bitvectorDivByZeroConst.wasSetByUser())
+ {
+ throw OptionException(
+ "--no-bv-div-zero-const is not supported with SyGuS");
+ }
+ Notice()
+ << "SmtEngine: setting bv-div-zero-const to true to support SyGuS"
+ << std::endl;
+ options::bitvectorDivByZeroConst.set(true);
+ }
+ if (!options::dtRewriteErrorSel.wasSetByUser())
+ {
+ options::dtRewriteErrorSel.set(true);
+ }
+ // do not miniscope
+ if (!options::miniscopeQuant.wasSetByUser())
+ {
+ options::miniscopeQuant.set(false);
+ }
+ if (!options::miniscopeQuantFreeVar.wasSetByUser())
+ {
+ options::miniscopeQuantFreeVar.set(false);
+ }
+ if (!options::quantSplit.wasSetByUser())
+ {
+ options::quantSplit.set(false);
+ }
+ // rewrite divk
+ if (!options::rewriteDivk.wasSetByUser())
+ {
+ options::rewriteDivk.set(true);
+ }
+ // do not do macros
+ if (!options::macrosQuant.wasSetByUser())
+ {
+ options::macrosQuant.set(false);
+ }
+ if (!options::cbqiPreRegInst.wasSetByUser())
+ {
+ options::cbqiPreRegInst.set(true);
+ }
+ }
+ // counterexample-guided instantiation for non-sygus
+ // enable if any possible quantifiers with arithmetic, datatypes or bitvectors
+ if ((logic.isQuantified()
+ && (logic.isTheoryEnabled(THEORY_ARITH)
+ || logic.isTheoryEnabled(THEORY_DATATYPES)
+ || logic.isTheoryEnabled(THEORY_BV)
+ || logic.isTheoryEnabled(THEORY_FP)))
+ || options::cbqiAll())
+ {
+ if (!options::cbqi.wasSetByUser())
+ {
+ options::cbqi.set(true);
+ }
+ // check whether we should apply full cbqi
+ if (logic.isPure(THEORY_BV))
+ {
+ if (!options::cbqiFullEffort.wasSetByUser())
+ {
+ options::cbqiFullEffort.set(true);
+ }
+ }
+ }
+ if (options::cbqi())
+ {
+ // must rewrite divk
+ if (!options::rewriteDivk.wasSetByUser())
+ {
+ options::rewriteDivk.set(true);
+ }
+ if (options::incrementalSolving())
+ {
+ // cannot do nested quantifier elimination in incremental mode
+ options::cbqiNestedQE.set(false);
+ }
+ if (logic.isPure(THEORY_ARITH) || logic.isPure(THEORY_BV))
+ {
+ if (!options::quantConflictFind.wasSetByUser())
+ {
+ options::quantConflictFind.set(false);
+ }
+ if (!options::instNoEntail.wasSetByUser())
+ {
+ options::instNoEntail.set(false);
+ }
+ if (!options::instWhenMode.wasSetByUser() && options::cbqiModel())
+ {
+ // only instantiation should happen at last call when model is avaiable
+ options::instWhenMode.set(options::InstWhenMode::LAST_CALL);
+ }
+ }
+ else
+ {
+ // only supported in pure arithmetic or pure BV
+ options::cbqiNestedQE.set(false);
+ }
+ // prenexing
+ if (options::cbqiNestedQE())
+ {
+ // only complete with prenex = disj_normal or normal
+ if (options::prenexQuant() <= options::PrenexQuantMode::DISJ_NORMAL)
+ {
+ options::prenexQuant.set(options::PrenexQuantMode::DISJ_NORMAL);
+ }
+ }
+ else if (options::globalNegate())
+ {
+ if (!options::prenexQuant.wasSetByUser())
+ {
+ options::prenexQuant.set(options::PrenexQuantMode::NONE);
+ }
+ }
+ }
+ // implied options...
+ if (options::strictTriggers())
+ {
+ if (!options::userPatternsQuant.wasSetByUser())
+ {
+ options::userPatternsQuant.set(options::UserPatMode::TRUST);
+ }
+ }
+ if (options::qcfMode.wasSetByUser() || options::qcfTConstraint())
+ {
+ options::quantConflictFind.set(true);
+ }
+ if (options::cbqiNestedQE())
+ {
+ options::prenexQuantUser.set(true);
+ if (!options::preSkolemQuant.wasSetByUser())
+ {
+ options::preSkolemQuant.set(true);
+ }
+ }
+ // for induction techniques
+ if (options::quantInduction())
+ {
+ if (!options::dtStcInduction.wasSetByUser())
+ {
+ options::dtStcInduction.set(true);
+ }
+ if (!options::intWfInduction.wasSetByUser())
+ {
+ options::intWfInduction.set(true);
+ }
+ }
+ if (options::dtStcInduction())
+ {
+ // try to remove ITEs from quantified formulas
+ if (!options::iteDtTesterSplitQuant.wasSetByUser())
+ {
+ options::iteDtTesterSplitQuant.set(true);
+ }
+ if (!options::iteLiftQuant.wasSetByUser())
+ {
+ options::iteLiftQuant.set(options::IteLiftQuantMode::ALL);
+ }
+ }
+ if (options::intWfInduction())
+ {
+ if (!options::purifyTriggers.wasSetByUser())
+ {
+ options::purifyTriggers.set(true);
+ }
+ }
+ if (options::conjectureNoFilter())
+ {
+ if (!options::conjectureFilterActiveTerms.wasSetByUser())
+ {
+ options::conjectureFilterActiveTerms.set(false);
+ }
+ if (!options::conjectureFilterCanonical.wasSetByUser())
+ {
+ options::conjectureFilterCanonical.set(false);
+ }
+ if (!options::conjectureFilterModel.wasSetByUser())
+ {
+ options::conjectureFilterModel.set(false);
+ }
+ }
+ if (options::conjectureGenPerRound.wasSetByUser())
+ {
+ if (options::conjectureGenPerRound() > 0)
+ {
+ options::conjectureGen.set(true);
+ }
+ else
+ {
+ options::conjectureGen.set(false);
+ }
+ }
+ // can't pre-skolemize nested quantifiers without UF theory
+ if (!logic.isTheoryEnabled(THEORY_UF) && options::preSkolemQuant())
+ {
+ if (!options::preSkolemQuantNested.wasSetByUser())
+ {
+ options::preSkolemQuantNested.set(false);
+ }
+ }
+ if (!logic.isTheoryEnabled(THEORY_DATATYPES))
+ {
+ options::quantDynamicSplit.set(options::QuantDSplitMode::NONE);
+ }
+
+ // until bugs 371,431 are fixed
+ if (!options::minisatUseElim.wasSetByUser())
+ {
+ // cannot use minisat elimination for logics where a theory solver
+ // introduces new literals into the search. This includes quantifiers
+ // (quantifier instantiation), and the lemma schemas used in non-linear
+ // and sets. We also can't use it if models are enabled.
+ if (logic.isTheoryEnabled(THEORY_SETS) || logic.isQuantified()
+ || options::produceModels() || options::produceAssignments()
+ || options::checkModels()
+ || (logic.isTheoryEnabled(THEORY_ARITH) && !logic.isLinear()))
+ {
+ options::minisatUseElim.set(false);
+ }
+ }
+
+ // For now, these array theory optimizations do not support model-building
+ if (options::produceModels() || options::produceAssignments()
+ || options::checkModels())
+ {
+ options::arraysOptimizeLinear.set(false);
+ options::arraysLazyRIntro1.set(false);
+ }
+
+ if (options::proof())
+ {
+ if (options::incrementalSolving())
+ {
+ if (options::incrementalSolving.wasSetByUser())
+ {
+ throw OptionException("--incremental is not supported with proofs");
+ }
+ Warning()
+ << "SmtEngine: turning off incremental solving mode (not yet "
+ "supported with --proof, try --tear-down-incremental instead)"
+ << std::endl;
+ smte.setOption("incremental", SExpr("false"));
+ }
+ if (logic > LogicInfo("QF_AUFBVLRA"))
+ {
+ throw OptionException(
+ "Proofs are only supported for sub-logics of QF_AUFBVLIA.");
+ }
+ if (options::bitvectorAlgebraicSolver())
+ {
+ if (options::bitvectorAlgebraicSolver.wasSetByUser())
+ {
+ throw OptionException(
+ "--bv-algebraic-solver is not supported with proofs");
+ }
+ Notice() << "SmtEngine: turning off bv algebraic solver to support proofs"
+ << std::endl;
+ options::bitvectorAlgebraicSolver.set(false);
+ }
+ if (options::bitvectorEqualitySolver())
+ {
+ if (options::bitvectorEqualitySolver.wasSetByUser())
+ {
+ throw OptionException("--bv-eq-solver is not supported with proofs");
+ }
+ Notice() << "SmtEngine: turning off bv eq solver to support proofs"
+ << std::endl;
+ options::bitvectorEqualitySolver.set(false);
+ }
+ if (options::bitvectorInequalitySolver())
+ {
+ if (options::bitvectorInequalitySolver.wasSetByUser())
+ {
+ throw OptionException(
+ "--bv-inequality-solver is not supported with proofs");
+ }
+ Notice() << "SmtEngine: turning off bv ineq solver to support proofs"
+ << std::endl;
+ options::bitvectorInequalitySolver.set(false);
+ }
+ }
+
+ if (!options::bitvectorEqualitySolver())
+ {
+ if (options::bvLazyRewriteExtf())
+ {
+ if (options::bvLazyRewriteExtf.wasSetByUser())
+ {
+ throw OptionException(
+ "--bv-lazy-rewrite-extf requires --bv-eq-solver to be set");
+ }
+ }
+ Trace("smt")
+ << "disabling bvLazyRewriteExtf since equality solver is disabled"
+ << std::endl;
+ options::bvLazyRewriteExtf.set(false);
+ }
+
+ if (!options::sygusExprMinerCheckUseExport())
+ {
+ if (options::sygusExprMinerCheckTimeout.wasSetByUser())
+ {
+ throw OptionException(
+ "--sygus-expr-miner-check-timeout=N requires "
+ "--sygus-expr-miner-check-use-export");
+ }
+ if (options::sygusRewSynthInput() || options::produceAbducts())
+ {
+ std::stringstream ss;
+ ss << (options::sygusRewSynthInput() ? "--sygus-rr-synth-input"
+ : "--produce-abducts");
+ ss << "requires --sygus-expr-miner-check-use-export";
+ throw OptionException(ss.str());
+ }
+ }
+
+ if (options::stringFMF() && !options::stringProcessLoopMode.wasSetByUser())
+ {
+ Trace("smt") << "settting stringProcessLoopMode to 'simple' since "
+ "--strings-fmf enabled"
+ << std::endl;
+ options::stringProcessLoopMode.set(options::ProcessLoopMode::SIMPLE);
+ }
+
+ // !!! All options that require disabling models go here
+ bool disableModels = false;
+ std::string sOptNoModel;
+ if (options::unconstrainedSimp.wasSetByUser() && options::unconstrainedSimp())
+ {
+ disableModels = true;
+ sOptNoModel = "unconstrained-simp";
+ }
+ else if (options::sortInference())
+ {
+ disableModels = true;
+ sOptNoModel = "sort-inference";
+ }
+ else if (options::minisatUseElim())
+ {
+ disableModels = true;
+ sOptNoModel = "minisat-elimination";
+ }
+ else if (logic.isTheoryEnabled(THEORY_ARITH) && !logic.isLinear()
+ && !options::nlExt())
+ {
+ disableModels = true;
+ sOptNoModel = "nonlinear arithmetic without nl-ext";
+ }
+ else if (options::globalNegate())
+ {
+ disableModels = true;
+ sOptNoModel = "global-negate";
+ }
+ if (disableModels)
+ {
+ if (options::produceModels())
+ {
+ if (options::produceModels.wasSetByUser())
+ {
+ std::stringstream ss;
+ ss << "Cannot use " << sOptNoModel << " with model generation.";
+ throw OptionException(ss.str());
+ }
+ Notice() << "SmtEngine: turning off produce-models to support "
+ << sOptNoModel << std::endl;
+ smte.setOption("produce-models", SExpr("false"));
+ }
+ if (options::produceAssignments())
+ {
+ if (options::produceAssignments.wasSetByUser())
+ {
+ std::stringstream ss;
+ ss << "Cannot use " << sOptNoModel
+ << " with model generation (produce-assignments).";
+ throw OptionException(ss.str());
+ }
+ Notice() << "SmtEngine: turning off produce-assignments to support "
+ << sOptNoModel << std::endl;
+ smte.setOption("produce-assignments", SExpr("false"));
+ }
+ if (options::checkModels())
+ {
+ if (options::checkModels.wasSetByUser())
+ {
+ std::stringstream ss;
+ ss << "Cannot use " << sOptNoModel
+ << " with model generation (check-models).";
+ throw OptionException(ss.str());
+ }
+ Notice() << "SmtEngine: turning off check-models to support "
+ << sOptNoModel << std::endl;
+ smte.setOption("check-models", SExpr("false"));
+ }
+ }
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/set_defaults.h b/src/smt/set_defaults.h
new file mode 100644
index 000000000..8871b0b38
--- /dev/null
+++ b/src/smt/set_defaults.h
@@ -0,0 +1,42 @@
+/********************* */
+/*! \file set_defaults.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Method for setting the default options of an SMT engine.
+ **/
+
+#ifndef CVC4__SMT__SET_DEFAULTS_H
+#define CVC4__SMT__SET_DEFAULTS_H
+
+#include "smt/smt_engine.h"
+#include "theory/logic_info.h"
+
+namespace CVC4 {
+namespace smt {
+
+/**
+ * The purpose of this method is to set the default options and update the logic
+ * info for SMT engine smte.
+ *
+ * The argument logic is a reference to the logic of SmtEngine, which can be
+ * updated by this method based on the current options and the logic itself.
+ *
+ * Note that currently, options are associated with the ExprManager. Thus, this
+ * call updates the options associated with the current ExprManager.
+ * If this designed is updated in the future so that SmtEngine has its own
+ * copy of options, this method should be updated accordingly so that it
+ * is responsible for updating this copy.
+ */
+void setDefaults(SmtEngine& smte, LogicInfo& logic);
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__SET_DEFAULTS_H */
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 7d78e93f9..2e1716543 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -86,6 +86,7 @@
#include "smt/managed_ostreams.h"
#include "smt/model_blocker.h"
#include "smt/model_core_builder.h"
+#include "smt/set_defaults.h"
#include "smt/smt_engine_scope.h"
#include "smt/term_formula_removal.h"
#include "smt/update_ostream.h"
@@ -293,40 +294,6 @@ class BeforeSearchListener : public Listener {
SmtEngine* d_smt;
}; /* class BeforeSearchListener */
-class UseTheoryListListener : public Listener {
- public:
- UseTheoryListListener(TheoryEngine* theoryEngine)
- : d_theoryEngine(theoryEngine)
- {}
-
- void notify() override
- {
- std::stringstream commaList(options::useTheoryList());
- std::string token;
-
- Debug("UseTheoryListListener") << "UseTheoryListListener::notify() "
- << options::useTheoryList() << std::endl;
-
- while(std::getline(commaList, token, ',')){
- if(token == "help") {
- puts(theory::useTheoryHelp);
- exit(1);
- }
- if(theory::useTheoryValidate(token)) {
- d_theoryEngine->enableTheoryAlternative(token);
- } else {
- throw OptionException(
- std::string("unknown option for --use-theory : `") + token +
- "'. Try --use-theory=help.");
- }
- }
- }
-
- private:
- TheoryEngine* d_theoryEngine;
-}; /* class UseTheoryListListener */
-
-
class SetDefaultExprDepthListener : public Listener {
public:
void notify() override
@@ -432,15 +399,11 @@ class SmtEnginePrivate : public NodeManagerListener {
/** Manager for the memory of --dump-to. */
ManagedDumpOStream d_managedDumpChannel;
- /** Manager for --replay-log. */
- ManagedReplayLogOstream d_managedReplayLog;
-
/**
* This list contains:
* softResourceOut
* hardResourceOut
* beforeSearchListener
- * UseTheoryListListener
*
* This needs to be deleted before both NodeManager's Options,
* SmtEngine, d_resourceManager, and TheoryEngine.
@@ -553,7 +516,6 @@ class SmtEnginePrivate : public NodeManagerListener {
d_managedRegularChannel(),
d_managedDiagnosticChannel(),
d_managedDumpChannel(),
- d_managedReplayLog(),
d_listenerRegistrations(new ListenerRegistrationList()),
d_propagator(true, true),
d_assertions(),
@@ -617,9 +579,6 @@ class SmtEnginePrivate : public NodeManagerListener {
d_listenerRegistrations->add(
nodeManagerOptions.registerDumpToFileNameListener(
new SetToDefaultSourceListener(&d_managedDumpChannel), true));
- d_listenerRegistrations->add(
- nodeManagerOptions.registerSetReplayLogFilename(
- new SetToDefaultSourceListener(&d_managedReplayLog), true));
}
catch (OptionException& e)
{
@@ -813,17 +772,6 @@ class SmtEnginePrivate : public NodeManagerListener {
return retval;
}
- void addUseTheoryListListener(TheoryEngine* theoryEngine){
- Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
- d_listenerRegistrations->add(
- nodeManagerOptions.registerUseTheoryListListener(
- new UseTheoryListListener(theoryEngine), true));
- }
-
- std::ostream* getReplayLog() const {
- return d_managedReplayLog.getReplayLog();
- }
-
//------------------------------- expression names
// implements setExpressionName, as described in smt_engine.h
void setExpressionName(Expr e, std::string name) {
@@ -869,12 +817,10 @@ SmtEngine::SmtEngine(ExprManager* em)
d_fullyInited(false),
d_queryMade(false),
d_needPostsolve(false),
- d_earlyTheoryPP(true),
d_globalNegation(false),
d_status(),
d_expectedStatus(),
d_smtMode(SMT_MODE_START),
- d_replayStream(nullptr),
d_private(nullptr),
d_statisticsRegistry(nullptr),
d_stats(nullptr)
@@ -923,10 +869,11 @@ void SmtEngine::finishInit()
#endif
}
- d_private->addUseTheoryListListener(getTheoryEngine());
+ // set the random seed
+ Random::getRandom().setSeed(options::seed());
// ensure that our heuristics are properly set up
- setDefaults();
+ setDefaults(*this, d_logic);
Trace("smt-debug") << "Making decision engine..." << std::endl;
@@ -935,11 +882,8 @@ void SmtEngine::finishInit()
* are unregistered by the obsolete PropEngine object before registered
* again by the new PropEngine object */
d_propEngine.reset(nullptr);
- d_propEngine.reset(new PropEngine(getTheoryEngine(),
- getContext(),
- getUserContext(),
- d_private->getReplayLog(),
- d_replayStream));
+ d_propEngine.reset(
+ new PropEngine(getTheoryEngine(), getContext(), getUserContext()));
Trace("smt-debug") << "Setting up theory engine..." << std::endl;
d_theoryEngine->setPropEngine(getPropEngine());
@@ -1014,9 +958,6 @@ void SmtEngine::finalOptionsAreSet() {
d_fullyInited = true;
Assert(d_logic.isLocked());
-
- d_propEngine->assertFormula(NodeManager::currentNM()->mkConst<bool>(true));
- d_propEngine->assertFormula(NodeManager::currentNM()->mkConst<bool>(false).notNode());
}
void SmtEngine::shutdown() {
@@ -1145,1216 +1086,6 @@ void SmtEngine::setLogicInternal()
d_logic.lock();
}
-void SmtEngine::setDefaults() {
- Random::getRandom().setSeed(options::seed());
- // Language-based defaults
- if (!options::bitvectorDivByZeroConst.wasSetByUser())
- {
- // Bitvector-divide-by-zero changed semantics in SMT LIB 2.6, thus we
- // set this option if the input format is SMT LIB 2.6. We also set this
- // option if we are sygus, since we assume SMT LIB 2.6 semantics for sygus.
- options::bitvectorDivByZeroConst.set(
- language::isInputLang_smt2_6(options::inputLanguage())
- || language::isInputLangSygus(options::inputLanguage()));
- }
- bool is_sygus = language::isInputLangSygus(options::inputLanguage());
-
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- if (options::produceModels()
- && (d_logic.isTheoryEnabled(THEORY_ARRAYS)
- || d_logic.isTheoryEnabled(THEORY_UF)))
- {
- if (options::bitblastMode.wasSetByUser()
- || options::produceModels.wasSetByUser())
- {
- throw OptionException(std::string(
- "Eager bit-blasting currently does not support model generation "
- "for the combination of bit-vectors with arrays or uinterpreted "
- "functions. Try --bitblast=lazy"));
- }
- Notice() << "SmtEngine: setting bit-blast mode to lazy to support model"
- << "generation" << endl;
- setOption("bitblastMode", SExpr("lazy"));
- }
- else if (!options::incrementalSolving())
- {
- options::ackermann.set(true);
- }
-
- if (options::incrementalSolving() && !d_logic.isPure(THEORY_BV))
- {
- throw OptionException(
- "Incremental eager bit-blasting is currently "
- "only supported for QF_BV. Try --bitblast=lazy.");
- }
- }
-
- if (options::solveIntAsBV() > 0)
- {
- d_logic = d_logic.getUnlockedCopy();
- d_logic.enableTheory(THEORY_BV);
- d_logic.lock();
- }
-
- if (options::solveBVAsInt() > 0)
- {
- if (d_logic.isTheoryEnabled(THEORY_BV))
- {
- d_logic = d_logic.getUnlockedCopy();
- d_logic.enableTheory(THEORY_ARITH);
- d_logic.arithNonLinear();
- d_logic.lock();
- }
- }
-
- // set options about ackermannization
- if (options::ackermann() && options::produceModels()
- && (d_logic.isTheoryEnabled(THEORY_ARRAYS)
- || d_logic.isTheoryEnabled(THEORY_UF)))
- {
- if (options::produceModels.wasSetByUser())
- {
- throw OptionException(std::string(
- "Ackermannization currently does not support model generation."));
- }
- Notice() << "SmtEngine: turn off ackermannization to support model"
- << "generation" << endl;
- options::ackermann.set(false);
- }
-
- if (options::ackermann())
- {
- if (options::incrementalSolving())
- {
- throw OptionException(
- "Incremental Ackermannization is currently not supported.");
- }
-
- if (d_logic.isQuantified())
- {
- throw LogicException("Cannot use Ackermannization on quantified formula");
- }
-
- if (d_logic.isTheoryEnabled(THEORY_UF))
- {
- d_logic = d_logic.getUnlockedCopy();
- d_logic.disableTheory(THEORY_UF);
- d_logic.lock();
- }
- if (d_logic.isTheoryEnabled(THEORY_ARRAYS))
- {
- d_logic = d_logic.getUnlockedCopy();
- d_logic.disableTheory(THEORY_ARRAYS);
- d_logic.lock();
- }
- }
-
- // Set default options associated with strings-exp. We also set these options
- // if we are using eager string preprocessing, which may introduce quantified
- // formulas at preprocess time.
- if (options::stringExp() || !options::stringLazyPreproc())
- {
- // We require quantifiers since extended functions reduce using them.
- if (!d_logic.isQuantified())
- {
- d_logic = d_logic.getUnlockedCopy();
- d_logic.enableQuantifiers();
- d_logic.lock();
- Trace("smt") << "turning on quantifier logic, for strings-exp"
- << std::endl;
- }
- // We require bounded quantifier handling.
- if (!options::fmfBound.wasSetByUser())
- {
- options::fmfBound.set( true );
- Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
- }
- // Turn off E-matching, since some bounded quantifiers introduced by strings
- // (e.g. for replaceall) admit matching loops.
- if (!options::eMatching.wasSetByUser())
- {
- options::eMatching.set(false);
- Trace("smt") << "turning off E-matching, for strings-exp" << std::endl;
- }
- // Do not eliminate extended arithmetic symbols from quantified formulas,
- // since some strategies, e.g. --re-elim-agg, introduce them.
- if (!options::elimExtArithQuant.wasSetByUser())
- {
- options::elimExtArithQuant.set(false);
- Trace("smt") << "turning off elim-ext-arith-quant, for strings-exp"
- << std::endl;
- }
- }
-
- // sygus inference may require datatypes
- if (!d_isInternalSubsolver)
- {
- if (options::produceAbducts() || options::sygusInference()
- || options::sygusRewSynthInput())
- {
- // since we are trying to recast as sygus, we assume the input is sygus
- is_sygus = true;
- }
- }
-
- // We now know whether the input is sygus. Update the logic to incorporate
- // the theories we need internally for handling sygus problems.
- if (is_sygus)
- {
- d_logic = d_logic.getUnlockedCopy();
- d_logic.enableSygus();
- d_logic.lock();
- }
-
- // sygus core connective requires unsat cores
- if (options::sygusCoreConnective())
- {
- options::unsatCores.set(true);
- }
-
- if ((options::checkModels() || options::checkSynthSol()
- || options::produceAbducts()
- || options::modelCoresMode() != options::ModelCoresMode::NONE
- || options::blockModelsMode() != options::BlockModelsMode::NONE)
- && !options::produceAssertions())
- {
- Notice() << "SmtEngine: turning on produce-assertions to support "
- << "option requiring assertions." << endl;
- setOption("produce-assertions", SExpr("true"));
- }
-
- // Disable options incompatible with incremental solving, unsat cores, and
- // proofs or output an error if enabled explicitly
- if (options::incrementalSolving() || options::unsatCores()
- || options::proof())
- {
- if (options::unconstrainedSimp())
- {
- if (options::unconstrainedSimp.wasSetByUser())
- {
- throw OptionException(
- "unconstrained simplification not supported with unsat "
- "cores/proofs/incremental solving");
- }
- Notice() << "SmtEngine: turning off unconstrained simplification to "
- "support unsat cores/proofs/incremental solving"
- << endl;
- options::unconstrainedSimp.set(false);
- }
- }
- else
- {
- // Turn on unconstrained simplification for QF_AUFBV
- if (!options::unconstrainedSimp.wasSetByUser())
- {
- // bool qf_sat = d_logic.isPure(THEORY_BOOL) &&
- // !d_logic.isQuantified(); bool uncSimp = false && !qf_sat &&
- // !options::incrementalSolving();
- bool uncSimp = !d_logic.isQuantified() && !options::produceModels()
- && !options::produceAssignments()
- && !options::checkModels()
- && (d_logic.isTheoryEnabled(THEORY_ARRAYS)
- && d_logic.isTheoryEnabled(THEORY_BV));
- Trace("smt") << "setting unconstrained simplification to " << uncSimp
- << endl;
- options::unconstrainedSimp.set(uncSimp);
- }
- }
-
- if (options::incrementalSolving() || options::proof())
- {
- if (options::sygusInference())
- {
- if (options::sygusInference.wasSetByUser())
- {
- throw OptionException(
- "sygus inference not supported with proofs/incremental solving");
- }
- Notice() << "SmtEngine: turning off sygus inference to support "
- "proofs/incremental solving"
- << std::endl;
- options::sygusInference.set(false);
- }
- }
-
- // Disable options incompatible with unsat cores and proofs or output an
- // error if enabled explicitly
- if (options::unsatCores() || options::proof())
- {
- if (options::simplificationMode() != options::SimplificationMode::NONE)
- {
- if (options::simplificationMode.wasSetByUser())
- {
- throw OptionException(
- "simplification not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off simplification to support unsat "
- "cores/proofs"
- << endl;
- options::simplificationMode.set(options::SimplificationMode::NONE);
- }
-
- if (options::pbRewrites())
- {
- if (options::pbRewrites.wasSetByUser())
- {
- throw OptionException(
- "pseudoboolean rewrites not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off pseudoboolean rewrites to support "
- "unsat cores/proofs"
- << endl;
- setOption("pb-rewrites", false);
- }
-
- if (options::sortInference())
- {
- if (options::sortInference.wasSetByUser())
- {
- throw OptionException(
- "sort inference not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off sort inference to support unsat "
- "cores/proofs"
- << endl;
- options::sortInference.set(false);
- }
-
- if (options::preSkolemQuant())
- {
- if (options::preSkolemQuant.wasSetByUser())
- {
- throw OptionException(
- "pre-skolemization not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off pre-skolemization to support unsat "
- "cores/proofs"
- << endl;
- options::preSkolemQuant.set(false);
- }
-
- if (options::solveBVAsInt() > 0)
- {
- /**
- * Operations on 1 bits are better handled as Boolean operations
- * than as integer operations.
- * Therefore, we enable bv-to-bool, which runs before
- * the translation to integers.
- */
- options::bitvectorToBool.set(true);
- }
-
- if (options::bitvectorToBool())
- {
- if (options::bitvectorToBool.wasSetByUser())
- {
- throw OptionException(
- "bv-to-bool not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat "
- "cores/proofs"
- << endl;
- options::bitvectorToBool.set(false);
- }
-
- if (options::boolToBitvector() != options::BoolToBVMode::OFF)
- {
- if (options::boolToBitvector.wasSetByUser())
- {
- throw OptionException(
- "bool-to-bv != off not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off bool-to-bv to support unsat "
- "cores/proofs"
- << endl;
- setOption("boolToBitvector", SExpr("off"));
- }
-
- if (options::bvIntroducePow2())
- {
- if (options::bvIntroducePow2.wasSetByUser())
- {
- throw OptionException(
- "bv-intro-pow2 not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off bv-intro-pow2 to support "
- "unsat-cores/proofs"
- << endl;
- setOption("bv-intro-pow2", false);
- }
-
- if (options::repeatSimp())
- {
- if (options::repeatSimp.wasSetByUser())
- {
- throw OptionException(
- "repeat-simp not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off repeat-simp to support unsat "
- "cores/proofs"
- << endl;
- setOption("repeat-simp", false);
- }
-
- if (options::globalNegate())
- {
- if (options::globalNegate.wasSetByUser())
- {
- throw OptionException(
- "global-negate not supported with unsat cores/proofs");
- }
- Notice() << "SmtEngine: turning off global-negate to support unsat "
- "cores/proofs"
- << endl;
- setOption("global-negate", false);
- }
-
- if (options::bitvectorAig())
- {
- throw OptionException(
- "bitblast-aig not supported with unsat cores/proofs");
- }
- }
- else
- {
- // by default, nonclausal simplification is off for QF_SAT
- if (!options::simplificationMode.wasSetByUser())
- {
- bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
- Trace("smt") << "setting simplification mode to <"
- << d_logic.getLogicString() << "> " << (!qf_sat) << endl;
- // simplification=none works better for SMT LIB benchmarks with
- // quantifiers, not others options::simplificationMode.set(qf_sat ||
- // quantifiers ? options::SimplificationMode::NONE :
- // options::SimplificationMode::BATCH);
- options::simplificationMode.set(qf_sat
- ? options::SimplificationMode::NONE
- : options::SimplificationMode::BATCH);
- }
- }
-
- if (options::cbqiBv() && d_logic.isQuantified())
- {
- if (options::boolToBitvector() != options::BoolToBVMode::OFF)
- {
- if (options::boolToBitvector.wasSetByUser())
- {
- throw OptionException(
- "bool-to-bv != off not supported with CBQI BV for quantified "
- "logics");
- }
- Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
- << endl;
- setOption("boolToBitvector", SExpr("off"));
- }
- }
-
- // cases where we need produce models
- if (!options::produceModels()
- && (options::produceAssignments() || options::sygusRewSynthCheck()
- || is_sygus))
- {
- Notice() << "SmtEngine: turning on produce-models" << endl;
- setOption("produce-models", SExpr("true"));
- }
-
- // Set the options for the theoryOf
- if(!options::theoryOfMode.wasSetByUser()) {
- if(d_logic.isSharingEnabled() &&
- !d_logic.isTheoryEnabled(THEORY_BV) &&
- !d_logic.isTheoryEnabled(THEORY_STRINGS) &&
- !d_logic.isTheoryEnabled(THEORY_SETS) ) {
- Trace("smt") << "setting theoryof-mode to term-based" << endl;
- options::theoryOfMode.set(options::TheoryOfMode::THEORY_OF_TERM_BASED);
- }
- }
-
- // strings require LIA, UF; widen the logic
- if(d_logic.isTheoryEnabled(THEORY_STRINGS)) {
- LogicInfo log(d_logic.getUnlockedCopy());
- // Strings requires arith for length constraints, and also UF
- if(!d_logic.isTheoryEnabled(THEORY_UF)) {
- Trace("smt") << "because strings are enabled, also enabling UF" << endl;
- log.enableTheory(THEORY_UF);
- }
- if(!d_logic.isTheoryEnabled(THEORY_ARITH) || d_logic.isDifferenceLogic() || !d_logic.areIntegersUsed()) {
- Trace("smt") << "because strings are enabled, also enabling linear integer arithmetic" << endl;
- log.enableTheory(THEORY_ARITH);
- log.enableIntegers();
- log.arithOnlyLinear();
- }
- d_logic = log;
- d_logic.lock();
- }
- if(d_logic.isTheoryEnabled(THEORY_ARRAYS) || d_logic.isTheoryEnabled(THEORY_DATATYPES) || d_logic.isTheoryEnabled(THEORY_SETS)) {
- if(!d_logic.isTheoryEnabled(THEORY_UF)) {
- LogicInfo log(d_logic.getUnlockedCopy());
- Trace("smt") << "because a theory that permits Boolean terms is enabled, also enabling UF" << endl;
- log.enableTheory(THEORY_UF);
- d_logic = log;
- d_logic.lock();
- }
- }
-
- // by default, symmetry breaker is on only for non-incremental QF_UF
- if(! options::ufSymmetryBreaker.wasSetByUser()) {
- bool qf_uf_noinc = d_logic.isPure(THEORY_UF) && !d_logic.isQuantified()
- && !options::incrementalSolving() && !options::proof()
- && !options::unsatCores();
- Trace("smt") << "setting uf symmetry breaker to " << qf_uf_noinc << endl;
- options::ufSymmetryBreaker.set(qf_uf_noinc);
- }
-
- // If in arrays, set the UF handler to arrays
- if(d_logic.isTheoryEnabled(THEORY_ARRAYS) && ( !d_logic.isQuantified() ||
- (d_logic.isQuantified() && !d_logic.isTheoryEnabled(THEORY_UF)))) {
- Theory::setUninterpretedSortOwner(THEORY_ARRAYS);
- } else {
- Theory::setUninterpretedSortOwner(THEORY_UF);
- }
-
- if(! options::simplifyWithCareEnabled.wasSetByUser() ){
- bool qf_aufbv = !d_logic.isQuantified() &&
- d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
- d_logic.isTheoryEnabled(THEORY_UF) &&
- d_logic.isTheoryEnabled(THEORY_BV);
-
- bool withCare = qf_aufbv;
- Trace("smt") << "setting ite simplify with care to " << withCare << endl;
- options::simplifyWithCareEnabled.set(withCare);
- }
- // Turn off array eager index splitting for QF_AUFLIA
- if(! options::arraysEagerIndexSplitting.wasSetByUser()) {
- if (not d_logic.isQuantified() &&
- d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
- d_logic.isTheoryEnabled(THEORY_UF) &&
- d_logic.isTheoryEnabled(THEORY_ARITH)) {
- Trace("smt") << "setting array eager index splitting to false" << endl;
- options::arraysEagerIndexSplitting.set(false);
- }
- }
- // Turn on model-based arrays for QF_AX (unless models are enabled)
- // if(! options::arraysModelBased.wasSetByUser()) {
- // if (not d_logic.isQuantified() &&
- // d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
- // d_logic.isPure(THEORY_ARRAYS) &&
- // !options::produceModels() &&
- // !options::checkModels()) {
- // Trace("smt") << "turning on model-based array solver" << endl;
- // options::arraysModelBased.set(true);
- // }
- // }
- // Turn on multiple-pass non-clausal simplification for QF_AUFBV
- if(! options::repeatSimp.wasSetByUser()) {
- bool repeatSimp = !d_logic.isQuantified() &&
- (d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
- d_logic.isTheoryEnabled(THEORY_UF) &&
- d_logic.isTheoryEnabled(THEORY_BV)) &&
- !options::unsatCores();
- Trace("smt") << "setting repeat simplification to " << repeatSimp << endl;
- options::repeatSimp.set(repeatSimp);
- }
-
- if (options::boolToBitvector() == options::BoolToBVMode::ALL
- && !d_logic.isTheoryEnabled(THEORY_BV))
- {
- if (options::boolToBitvector.wasSetByUser())
- {
- throw OptionException(
- "bool-to-bv=all not supported for non-bitvector logics.");
- }
- Notice() << "SmtEngine: turning off bool-to-bv for non-bv logic: "
- << d_logic.getLogicString() << std::endl;
- setOption("boolToBitvector", SExpr("off"));
- }
-
- if (! options::bvEagerExplanations.wasSetByUser() &&
- d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
- d_logic.isTheoryEnabled(THEORY_BV)) {
- Trace("smt") << "enabling eager bit-vector explanations " << endl;
- options::bvEagerExplanations.set(true);
- }
-
- // Turn on arith rewrite equalities only for pure arithmetic
- if(! options::arithRewriteEq.wasSetByUser()) {
- bool arithRewriteEq = d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isQuantified();
- Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq << endl;
- options::arithRewriteEq.set(arithRewriteEq);
- }
- if(! options::arithHeuristicPivots.wasSetByUser()) {
- int16_t heuristicPivots = 5;
- if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()) {
- if(d_logic.isDifferenceLogic()) {
- heuristicPivots = -1;
- } else if(!d_logic.areIntegersUsed()) {
- heuristicPivots = 0;
- }
- }
- Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots << endl;
- options::arithHeuristicPivots.set(heuristicPivots);
- }
- if(! options::arithPivotThreshold.wasSetByUser()){
- uint16_t pivotThreshold = 2;
- if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()){
- if(d_logic.isDifferenceLogic()){
- pivotThreshold = 16;
- }
- }
- Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold << endl;
- options::arithPivotThreshold.set(pivotThreshold);
- }
- if(! options::arithStandardCheckVarOrderPivots.wasSetByUser()){
- int16_t varOrderPivots = -1;
- if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()){
- varOrderPivots = 200;
- }
- Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots << endl;
- options::arithStandardCheckVarOrderPivots.set(varOrderPivots);
- }
- // Turn off early theory preprocessing if arithRewriteEq is on
- if (options::arithRewriteEq()) {
- d_earlyTheoryPP = false;
- }
- if (d_logic.isPure(THEORY_ARITH) && !d_logic.areRealsUsed())
- {
- if (!options::nlExtTangentPlanesInterleave.wasSetByUser())
- {
- Trace("smt") << "setting nlExtTangentPlanesInterleave to true" << endl;
- options::nlExtTangentPlanesInterleave.set(true);
- }
- }
-
- // Set decision mode based on logic (if not set by user)
- if(!options::decisionMode.wasSetByUser()) {
- options::DecisionMode decMode =
- // sygus uses internal
- is_sygus ? options::DecisionMode::INTERNAL :
- // ALL
- d_logic.hasEverything()
- ? options::DecisionMode::JUSTIFICATION
- : ( // QF_BV
- (not d_logic.isQuantified() && d_logic.isPure(THEORY_BV)) ||
- // QF_AUFBV or QF_ABV or QF_UFBV
- (not d_logic.isQuantified()
- && (d_logic.isTheoryEnabled(THEORY_ARRAYS)
- || d_logic.isTheoryEnabled(THEORY_UF))
- && d_logic.isTheoryEnabled(THEORY_BV))
- ||
- // QF_AUFLIA (and may be ends up enabling
- // QF_AUFLRA?)
- (not d_logic.isQuantified()
- && d_logic.isTheoryEnabled(THEORY_ARRAYS)
- && d_logic.isTheoryEnabled(THEORY_UF)
- && d_logic.isTheoryEnabled(THEORY_ARITH))
- ||
- // QF_LRA
- (not d_logic.isQuantified()
- && d_logic.isPure(THEORY_ARITH)
- && d_logic.isLinear()
- && !d_logic.isDifferenceLogic()
- && !d_logic.areIntegersUsed())
- ||
- // Quantifiers
- d_logic.isQuantified() ||
- // Strings
- d_logic.isTheoryEnabled(THEORY_STRINGS)
- ? options::DecisionMode::JUSTIFICATION
- : options::DecisionMode::INTERNAL);
-
- bool stoponly =
- // ALL
- d_logic.hasEverything() || d_logic.isTheoryEnabled(THEORY_STRINGS) ? false :
- ( // QF_AUFLIA
- (not d_logic.isQuantified() &&
- d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
- d_logic.isTheoryEnabled(THEORY_UF) &&
- d_logic.isTheoryEnabled(THEORY_ARITH)
- ) ||
- // QF_LRA
- (not d_logic.isQuantified() &&
- d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
- )
- ? true : false
- );
-
- Trace("smt") << "setting decision mode to " << decMode << endl;
- options::decisionMode.set(decMode);
- options::decisionStopOnly.set(stoponly);
- }
- if( options::incrementalSolving() ){
- //disable modes not supported by incremental
- options::sortInference.set( false );
- options::ufssFairnessMonotone.set( false );
- options::quantEpr.set( false );
- options::globalNegate.set(false);
- }
- if( d_logic.hasCardinalityConstraints() ){
- //must have finite model finding on
- options::finiteModelFind.set( true );
- }
-
- //if it contains a theory with non-termination, do not strictly enforce that quantifiers and theory combination must be interleaved
- if( d_logic.isTheoryEnabled(THEORY_STRINGS) || (d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()) ){
- if( !options::instWhenStrictInterleave.wasSetByUser() ){
- options::instWhenStrictInterleave.set( false );
- }
- }
-
- if( options::instMaxLevel()!=-1 ){
- Notice() << "SmtEngine: turning off cbqi to support instMaxLevel" << endl;
- options::cbqi.set(false);
- }
- // Do we need to track instantiations?
- // Needed for sygus due to single invocation techniques.
- if (options::cbqiNestedQE()
- || (options::proof() && !options::trackInstLemmas.wasSetByUser())
- || is_sygus)
- {
- options::trackInstLemmas.set( true );
- }
-
- if( ( options::fmfBoundLazy.wasSetByUser() && options::fmfBoundLazy() ) ||
- ( options::fmfBoundInt.wasSetByUser() && options::fmfBoundInt() ) ) {
- options::fmfBound.set( true );
- }
- //now have determined whether fmfBoundInt is on/off
- //apply fmfBoundInt options
- if( options::fmfBound() ){
- if (!options::mbqiMode.wasSetByUser()
- || (options::mbqiMode() != options::MbqiMode::NONE
- && options::mbqiMode() != options::MbqiMode::FMC))
- {
- //if bounded integers are set, use no MBQI by default
- options::mbqiMode.set(options::MbqiMode::NONE);
- }
- if( ! options::prenexQuant.wasSetByUser() ){
- options::prenexQuant.set(options::PrenexQuantMode::NONE);
- }
- }
- if( options::ufHo() ){
- //if higher-order, then current variants of model-based instantiation cannot be used
- if (options::mbqiMode() != options::MbqiMode::NONE)
- {
- options::mbqiMode.set(options::MbqiMode::NONE);
- }
- if (!options::hoElimStoreAx.wasSetByUser())
- {
- // by default, use store axioms only if --ho-elim is set
- options::hoElimStoreAx.set(options::hoElim());
- }
- }
- if( options::fmfFunWellDefinedRelevant() ){
- if( !options::fmfFunWellDefined.wasSetByUser() ){
- options::fmfFunWellDefined.set( true );
- }
- }
- if( options::fmfFunWellDefined() ){
- if( !options::finiteModelFind.wasSetByUser() ){
- options::finiteModelFind.set( true );
- }
- }
- //EPR
- if( options::quantEpr() ){
- if( !options::preSkolemQuant.wasSetByUser() ){
- options::preSkolemQuant.set( true );
- }
- }
-
- //now, have determined whether finite model find is on/off
- //apply finite model finding options
- if( options::finiteModelFind() ){
- //apply conservative quantifiers splitting
- if( !options::quantDynamicSplit.wasSetByUser() ){
- options::quantDynamicSplit.set(options::QuantDSplitMode::DEFAULT);
- }
- //do not eliminate extended arithmetic symbols from quantified formulas
- if( !options::elimExtArithQuant.wasSetByUser() ){
- options::elimExtArithQuant.set( false );
- }
- if( !options::eMatching.wasSetByUser() ){
- options::eMatching.set( options::fmfInstEngine() );
- }
- if( !options::instWhenMode.wasSetByUser() ){
- //instantiate only on last call
- if( options::eMatching() ){
- options::instWhenMode.set(options::InstWhenMode::LAST_CALL);
- }
- }
- }
-
- // apply sygus options
- // if we are attempting to rewrite everything to SyGuS, use sygus()
- if (is_sygus)
- {
- if (!options::sygus())
- {
- Trace("smt") << "turning on sygus" << std::endl;
- }
- options::sygus.set(true);
- // must use Ferrante/Rackoff for real arithmetic
- if (!options::cbqiMidpoint.wasSetByUser())
- {
- options::cbqiMidpoint.set(true);
- }
- if (options::sygusRepairConst())
- {
- if (!options::cbqi.wasSetByUser())
- {
- options::cbqi.set(true);
- }
- }
- if (options::sygusInference())
- {
- // optimization: apply preskolemization, makes it succeed more often
- if (!options::preSkolemQuant.wasSetByUser())
- {
- options::preSkolemQuant.set(true);
- }
- if (!options::preSkolemQuantNested.wasSetByUser())
- {
- options::preSkolemQuantNested.set(true);
- }
- }
- //counterexample-guided instantiation for sygus
- if( !options::cegqiSingleInvMode.wasSetByUser() ){
- options::cegqiSingleInvMode.set(options::CegqiSingleInvMode::USE);
- }
- if( !options::quantConflictFind.wasSetByUser() ){
- options::quantConflictFind.set( false );
- }
- if( !options::instNoEntail.wasSetByUser() ){
- options::instNoEntail.set( false );
- }
- if (!options::cbqiFullEffort.wasSetByUser())
- {
- // should use full effort cbqi for single invocation and repair const
- options::cbqiFullEffort.set(true);
- }
- if (options::sygusRew())
- {
- options::sygusRewSynth.set(true);
- options::sygusRewVerify.set(true);
- }
- if (options::sygusRewSynthInput())
- {
- // If we are using synthesis rewrite rules from input, we use
- // sygusRewSynth after preprocessing. See passes/synth_rew_rules.h for
- // details on this technique.
- options::sygusRewSynth.set(true);
- // we should not use the extended rewriter, since we are interested
- // in rewrites that are not in the main rewriter
- if (!options::sygusExtRew.wasSetByUser())
- {
- options::sygusExtRew.set(false);
- }
- }
- // Whether we must use "basic" sygus algorithms. A non-basic sygus algorithm
- // is one that is specialized for returning a single solution. Non-basic
- // sygus algorithms currently include the PBE solver, UNIF+PI, static
- // template inference for invariant synthesis, and single invocation
- // techniques.
- bool reqBasicSygus = false;
- if (options::produceAbducts())
- {
- // if doing abduction, we should filter strong solutions
- if (!options::sygusFilterSolMode.wasSetByUser())
- {
- options::sygusFilterSolMode.set(options::SygusFilterSolMode::STRONG);
- }
- // we must use basic sygus algorithms, since e.g. we require checking
- // a sygus side condition for consistency with axioms.
- reqBasicSygus = true;
- }
- if (options::sygusRewSynth() || options::sygusRewVerify()
- || options::sygusQueryGen())
- {
- // rewrite rule synthesis implies that sygus stream must be true
- options::sygusStream.set(true);
- }
- if (options::sygusStream() || options::incrementalSolving())
- {
- // Streaming and incremental mode are incompatible with techniques that
- // focus the search towards finding a single solution.
- reqBasicSygus = true;
- }
- // Now, disable options for non-basic sygus algorithms, if necessary.
- if (reqBasicSygus)
- {
- if (!options::sygusUnifPbe.wasSetByUser())
- {
- options::sygusUnifPbe.set(false);
- }
- if (options::sygusUnifPi.wasSetByUser())
- {
- options::sygusUnifPi.set(options::SygusUnifPiMode::NONE);
- }
- if (!options::sygusInvTemplMode.wasSetByUser())
- {
- options::sygusInvTemplMode.set(options::SygusInvTemplMode::NONE);
- }
- if (!options::cegqiSingleInvMode.wasSetByUser())
- {
- options::cegqiSingleInvMode.set(options::CegqiSingleInvMode::NONE);
- }
- }
- //do not allow partial functions
- if (!options::bitvectorDivByZeroConst())
- {
- if (options::bitvectorDivByZeroConst.wasSetByUser())
- {
- throw OptionException(
- "--no-bv-div-zero-const is not supported with SyGuS");
- }
- Notice()
- << "SmtEngine: setting bv-div-zero-const to true to support SyGuS"
- << std::endl;
- options::bitvectorDivByZeroConst.set( true );
- }
- if( !options::dtRewriteErrorSel.wasSetByUser() ){
- options::dtRewriteErrorSel.set( true );
- }
- //do not miniscope
- if( !options::miniscopeQuant.wasSetByUser() ){
- options::miniscopeQuant.set( false );
- }
- if( !options::miniscopeQuantFreeVar.wasSetByUser() ){
- options::miniscopeQuantFreeVar.set( false );
- }
- if (!options::quantSplit.wasSetByUser())
- {
- options::quantSplit.set(false);
- }
- //rewrite divk
- if( !options::rewriteDivk.wasSetByUser()) {
- options::rewriteDivk.set( true );
- }
- //do not do macros
- if( !options::macrosQuant.wasSetByUser()) {
- options::macrosQuant.set( false );
- }
- if( !options::cbqiPreRegInst.wasSetByUser()) {
- options::cbqiPreRegInst.set( true );
- }
- }
- //counterexample-guided instantiation for non-sygus
- // enable if any possible quantifiers with arithmetic, datatypes or bitvectors
- if ((d_logic.isQuantified()
- && (d_logic.isTheoryEnabled(THEORY_ARITH)
- || d_logic.isTheoryEnabled(THEORY_DATATYPES)
- || d_logic.isTheoryEnabled(THEORY_BV)
- || d_logic.isTheoryEnabled(THEORY_FP)))
- || options::cbqiAll())
- {
- if( !options::cbqi.wasSetByUser() ){
- options::cbqi.set( true );
- }
- // check whether we should apply full cbqi
- if (d_logic.isPure(THEORY_BV))
- {
- if (!options::cbqiFullEffort.wasSetByUser())
- {
- options::cbqiFullEffort.set(true);
- }
- }
- }
- if( options::cbqi() ){
- //must rewrite divk
- if( !options::rewriteDivk.wasSetByUser()) {
- options::rewriteDivk.set( true );
- }
- if (options::incrementalSolving())
- {
- // cannot do nested quantifier elimination in incremental mode
- options::cbqiNestedQE.set(false);
- }
- if (d_logic.isPure(THEORY_ARITH) || d_logic.isPure(THEORY_BV))
- {
- if( !options::quantConflictFind.wasSetByUser() ){
- options::quantConflictFind.set( false );
- }
- if( !options::instNoEntail.wasSetByUser() ){
- options::instNoEntail.set( false );
- }
- if( !options::instWhenMode.wasSetByUser() && options::cbqiModel() ){
- //only instantiation should happen at last call when model is avaiable
- options::instWhenMode.set(options::InstWhenMode::LAST_CALL);
- }
- }else{
- // only supported in pure arithmetic or pure BV
- options::cbqiNestedQE.set(false);
- }
- // prenexing
- if (options::cbqiNestedQE())
- {
- // only complete with prenex = disj_normal or normal
- if (options::prenexQuant() <= options::PrenexQuantMode::DISJ_NORMAL)
- {
- options::prenexQuant.set(options::PrenexQuantMode::DISJ_NORMAL);
- }
- }
- else if (options::globalNegate())
- {
- if (!options::prenexQuant.wasSetByUser())
- {
- options::prenexQuant.set(options::PrenexQuantMode::NONE);
- }
- }
- }
- //implied options...
- if( options::strictTriggers() ){
- if( !options::userPatternsQuant.wasSetByUser() ){
- options::userPatternsQuant.set(options::UserPatMode::TRUST);
- }
- }
- if( options::qcfMode.wasSetByUser() || options::qcfTConstraint() ){
- options::quantConflictFind.set( true );
- }
- if( options::cbqiNestedQE() ){
- options::prenexQuantUser.set( true );
- if( !options::preSkolemQuant.wasSetByUser() ){
- options::preSkolemQuant.set( true );
- }
- }
- //for induction techniques
- if( options::quantInduction() ){
- if( !options::dtStcInduction.wasSetByUser() ){
- options::dtStcInduction.set( true );
- }
- if( !options::intWfInduction.wasSetByUser() ){
- options::intWfInduction.set( true );
- }
- }
- if( options::dtStcInduction() ){
- //try to remove ITEs from quantified formulas
- if( !options::iteDtTesterSplitQuant.wasSetByUser() ){
- options::iteDtTesterSplitQuant.set( true );
- }
- if( !options::iteLiftQuant.wasSetByUser() ){
- options::iteLiftQuant.set(options::IteLiftQuantMode::ALL);
- }
- }
- if( options::intWfInduction() ){
- if( !options::purifyTriggers.wasSetByUser() ){
- options::purifyTriggers.set( true );
- }
- }
- if( options::conjectureNoFilter() ){
- if( !options::conjectureFilterActiveTerms.wasSetByUser() ){
- options::conjectureFilterActiveTerms.set( false );
- }
- if( !options::conjectureFilterCanonical.wasSetByUser() ){
- options::conjectureFilterCanonical.set( false );
- }
- if( !options::conjectureFilterModel.wasSetByUser() ){
- options::conjectureFilterModel.set( false );
- }
- }
- if( options::conjectureGenPerRound.wasSetByUser() ){
- if( options::conjectureGenPerRound()>0 ){
- options::conjectureGen.set( true );
- }else{
- options::conjectureGen.set( false );
- }
- }
- //can't pre-skolemize nested quantifiers without UF theory
- if( !d_logic.isTheoryEnabled(THEORY_UF) && options::preSkolemQuant() ){
- if( !options::preSkolemQuantNested.wasSetByUser() ){
- options::preSkolemQuantNested.set( false );
- }
- }
- if( !d_logic.isTheoryEnabled(THEORY_DATATYPES) ){
- options::quantDynamicSplit.set(options::QuantDSplitMode::NONE);
- }
-
- //until bugs 371,431 are fixed
- if( ! options::minisatUseElim.wasSetByUser()){
- // cannot use minisat elimination for logics where a theory solver
- // introduces new literals into the search. This includes quantifiers
- // (quantifier instantiation), and the lemma schemas used in non-linear
- // and sets. We also can't use it if models are enabled.
- if (d_logic.isTheoryEnabled(THEORY_SETS) || d_logic.isQuantified()
- || options::produceModels() || options::produceAssignments()
- || options::checkModels()
- || (d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()))
- {
- options::minisatUseElim.set( false );
- }
- }
-
- // For now, these array theory optimizations do not support model-building
- if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
- options::arraysOptimizeLinear.set(false);
- options::arraysLazyRIntro1.set(false);
- }
-
- if (options::proof())
- {
- if (options::incrementalSolving())
- {
- if (options::incrementalSolving.wasSetByUser())
- {
- throw OptionException("--incremental is not supported with proofs");
- }
- Warning()
- << "SmtEngine: turning off incremental solving mode (not yet "
- "supported with --proof, try --tear-down-incremental instead)"
- << endl;
- setOption("incremental", SExpr("false"));
- }
- if (d_logic > LogicInfo("QF_AUFBVLRA"))
- {
- throw OptionException(
- "Proofs are only supported for sub-logics of QF_AUFBVLIA.");
- }
- if (options::bitvectorAlgebraicSolver())
- {
- if (options::bitvectorAlgebraicSolver.wasSetByUser())
- {
- throw OptionException(
- "--bv-algebraic-solver is not supported with proofs");
- }
- Notice() << "SmtEngine: turning off bv algebraic solver to support proofs"
- << std::endl;
- options::bitvectorAlgebraicSolver.set(false);
- }
- if (options::bitvectorEqualitySolver())
- {
- if (options::bitvectorEqualitySolver.wasSetByUser())
- {
- throw OptionException("--bv-eq-solver is not supported with proofs");
- }
- Notice() << "SmtEngine: turning off bv eq solver to support proofs"
- << std::endl;
- options::bitvectorEqualitySolver.set(false);
- }
- if (options::bitvectorInequalitySolver())
- {
- if (options::bitvectorInequalitySolver.wasSetByUser())
- {
- throw OptionException(
- "--bv-inequality-solver is not supported with proofs");
- }
- Notice() << "SmtEngine: turning off bv ineq solver to support proofs"
- << std::endl;
- options::bitvectorInequalitySolver.set(false);
- }
- }
-
- if (!options::bitvectorEqualitySolver())
- {
- if (options::bvLazyRewriteExtf())
- {
- if (options::bvLazyRewriteExtf.wasSetByUser())
- {
- throw OptionException(
- "--bv-lazy-rewrite-extf requires --bv-eq-solver to be set");
- }
- }
- Trace("smt")
- << "disabling bvLazyRewriteExtf since equality solver is disabled"
- << endl;
- options::bvLazyRewriteExtf.set(false);
- }
-
- if (!options::sygusExprMinerCheckUseExport())
- {
- if (options::sygusExprMinerCheckTimeout.wasSetByUser())
- {
- throw OptionException(
- "--sygus-expr-miner-check-timeout=N requires "
- "--sygus-expr-miner-check-use-export");
- }
- if (options::sygusRewSynthInput() || options::produceAbducts())
- {
- std::stringstream ss;
- ss << (options::sygusRewSynthInput() ? "--sygus-rr-synth-input"
- : "--produce-abducts");
- ss << "requires --sygus-expr-miner-check-use-export";
- throw OptionException(ss.str());
- }
- }
-
- if (options::stringFMF() && !options::stringProcessLoopMode.wasSetByUser())
- {
- Trace("smt") << "settting stringProcessLoopMode to 'simple' since "
- "--strings-fmf enabled"
- << endl;
- options::stringProcessLoopMode.set(options::ProcessLoopMode::SIMPLE);
- }
-
- // !!! All options that require disabling models go here
- bool disableModels = false;
- std::string sOptNoModel;
- if (options::unconstrainedSimp.wasSetByUser() && options::unconstrainedSimp())
- {
- disableModels = true;
- sOptNoModel = "unconstrained-simp";
- }
- else if (options::sortInference())
- {
- disableModels = true;
- sOptNoModel = "sort-inference";
- }
- else if (options::minisatUseElim())
- {
- disableModels = true;
- sOptNoModel = "minisat-elimination";
- }
- else if (d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()
- && !options::nlExt())
- {
- disableModels = true;
- sOptNoModel = "nonlinear arithmetic without nl-ext";
- }
- else if (options::globalNegate())
- {
- disableModels = true;
- sOptNoModel = "global-negate";
- }
- if (disableModels)
- {
- if (options::produceModels())
- {
- if (options::produceModels.wasSetByUser())
- {
- std::stringstream ss;
- ss << "Cannot use " << sOptNoModel << " with model generation.";
- throw OptionException(ss.str());
- }
- Notice() << "SmtEngine: turning off produce-models to support "
- << sOptNoModel << endl;
- setOption("produce-models", SExpr("false"));
- }
- if (options::produceAssignments())
- {
- if (options::produceAssignments.wasSetByUser())
- {
- std::stringstream ss;
- ss << "Cannot use " << sOptNoModel
- << " with model generation (produce-assignments).";
- throw OptionException(ss.str());
- }
- Notice() << "SmtEngine: turning off produce-assignments to support "
- << sOptNoModel << endl;
- setOption("produce-assignments", SExpr("false"));
- }
- if (options::checkModels())
- {
- if (options::checkModels.wasSetByUser())
- {
- std::stringstream ss;
- ss << "Cannot use " << sOptNoModel
- << " with model generation (check-models).";
- throw OptionException(ss.str());
- }
- Notice() << "SmtEngine: turning off check-models to support "
- << sOptNoModel << endl;
- setOption("check-models", SExpr("false"));
- }
- }
-}
-
void SmtEngine::setProblemExtended()
{
d_smtMode = SMT_MODE_ASSERT;
@@ -2966,7 +1697,8 @@ bool SmtEnginePrivate::simplifyAssertions()
d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertions.ref());
// Theory preprocessing
- if (d_smt.d_earlyTheoryPP)
+ bool doEarlyTheoryPp = !options::arithRewriteEq();
+ if (doEarlyTheoryPp)
{
d_passes["theory-preprocess"]->apply(&d_assertions);
}
@@ -3034,7 +1766,7 @@ Result SmtEngine::check() {
resourceManager->out()) {
Result::UnknownExplanation why = resourceManager->outOfResources() ?
Result::RESOURCEOUT : Result::TIMEOUT;
- return Result(Result::VALIDITY_UNKNOWN, why, d_filename);
+ return Result(Result::ENTAILMENT_UNKNOWN, why, d_filename);
}
// Make sure the prop layer has all of the assertions
@@ -3059,7 +1791,8 @@ Result SmtEngine::check() {
Result SmtEngine::quickCheck() {
Assert(d_fullyInited);
Trace("smt") << "SMT quickCheck()" << endl;
- return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
+ return Result(
+ Result::ENTAILMENT_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
}
theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const
@@ -3075,7 +1808,8 @@ theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const
{
std::stringstream ss;
ss << "Cannot " << c
- << " unless immediately preceded by SAT/INVALID or UNKNOWN response.";
+ << " unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN "
+ "response.";
throw RecoverableModalException(ss.str().c_str());
}
@@ -3648,35 +2382,34 @@ Result SmtEngine::checkSat(const vector<Expr>& assumptions, bool inUnsatCore)
return checkSatisfiability(assumptions, inUnsatCore, false);
}
-Result SmtEngine::query(const Expr& assumption, bool inUnsatCore)
+Result SmtEngine::checkEntailed(const Expr& expr, bool inUnsatCore)
{
- Dump("benchmark") << QueryCommand(assumption, inUnsatCore);
- return checkSatisfiability(assumption.isNull()
- ? std::vector<Expr>()
- : std::vector<Expr>{assumption},
- inUnsatCore,
- true)
- .asValidityResult();
+ Dump("benchmark") << QueryCommand(expr, inUnsatCore);
+ return checkSatisfiability(
+ expr.isNull() ? std::vector<Expr>() : std::vector<Expr>{expr},
+ inUnsatCore,
+ true)
+ .asEntailmentResult();
}
-Result SmtEngine::query(const vector<Expr>& assumptions, bool inUnsatCore)
+Result SmtEngine::checkEntailed(const vector<Expr>& exprs, bool inUnsatCore)
{
- return checkSatisfiability(assumptions, inUnsatCore, true).asValidityResult();
+ return checkSatisfiability(exprs, inUnsatCore, true).asEntailmentResult();
}
Result SmtEngine::checkSatisfiability(const Expr& expr,
bool inUnsatCore,
- bool isQuery)
+ bool isEntailmentCheck)
{
return checkSatisfiability(
expr.isNull() ? std::vector<Expr>() : std::vector<Expr>{expr},
inUnsatCore,
- isQuery);
+ isEntailmentCheck);
}
Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
bool inUnsatCore,
- bool isQuery)
+ bool isEntailmentCheck)
{
try
{
@@ -3684,7 +2417,8 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
finalOptionsAreSet();
doPendingPops();
- Trace("smt") << "SmtEngine::" << (isQuery ? "query" : "checkSat") << "("
+ Trace("smt") << "SmtEngine::"
+ << (isEntailmentCheck ? "checkEntailed" : "checkSat") << "("
<< assumptions << ")" << endl;
if(d_queryMade && !options::incrementalSolving()) {
@@ -3702,7 +2436,7 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
setProblemExtended();
- if (isQuery)
+ if (isEntailmentCheck)
{
size_t size = assumptions.size();
if (size > 1)
@@ -3808,8 +2542,8 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
d_smtMode = SMT_MODE_SAT_UNKNOWN;
}
- Trace("smt") << "SmtEngine::" << (isQuery ? "query" : "checkSat") << "("
- << assumptions << ") => " << r << endl;
+ Trace("smt") << "SmtEngine::" << (isEntailmentCheck ? "query" : "checkSat")
+ << "(" << assumptions << ") => " << r << endl;
// Check that SAT results generate a model correctly.
if(options::checkModels()) {
@@ -3855,7 +2589,7 @@ vector<Expr> SmtEngine::getUnsatAssumptions(void)
{
throw RecoverableModalException(
"Cannot get unsat assumptions unless immediately preceded by "
- "UNSAT/VALID response.");
+ "UNSAT/ENTAILED.");
}
finalOptionsAreSet();
if (Dump.isOn("benchmark"))
@@ -3893,7 +2627,7 @@ Result SmtEngine::assertFormula(const Expr& ex, bool inUnsatCore)
}
bool maybeHasFv = language::isInputLangSygus(options::inputLanguage());
d_private->addFormula(e.getNode(), inUnsatCore, true, false, maybeHasFv);
- return quickCheck().asValidityResult();
+ return quickCheck().asEntailmentResult();
}/* SmtEngine::assertFormula() */
/*
@@ -4486,13 +3220,13 @@ std::pair<Expr, Expr> SmtEngine::getSepHeapAndNilExpr(void)
Expr heap;
Expr nil;
Model* m = getAvailableModel("get separation logic heap and nil");
- if (m->getHeapModel(heap, nil))
+ if (!m->getHeapModel(heap, nil))
{
- return std::make_pair(heap, nil);
+ InternalError()
+ << "SmtEngine::getSepHeapAndNilExpr(): failed to obtain heap/nil "
+ "expressions from theory model.";
}
- InternalError()
- << "SmtEngine::getSepHeapAndNilExpr(): failed to obtain heap/nil "
- "expressions from theory model.";
+ return std::make_pair(heap, nil);
}
std::vector<Expr> SmtEngine::getExpandedAssertions()
@@ -4562,8 +3296,8 @@ UnsatCore SmtEngine::getUnsatCoreInternal()
if (d_smtMode != SMT_MODE_UNSAT)
{
throw RecoverableModalException(
- "Cannot get an unsat core unless immediately preceded by UNSAT/VALID "
- "response.");
+ "Cannot get an unsat core unless immediately preceded by "
+ "UNSAT/ENTAILED response.");
}
d_proofManager->traceUnsatCore(); // just to trigger core creation
@@ -5068,7 +3802,7 @@ const Proof& SmtEngine::getProof()
if (d_smtMode != SMT_MODE_UNSAT)
{
throw RecoverableModalException(
- "Cannot get a proof unless immediately preceded by UNSAT/VALID "
+ "Cannot get a proof unless immediately preceded by UNSAT/ENTAILED "
"response.");
}
@@ -5546,11 +4280,8 @@ void SmtEngine::resetAssertions()
* statistics are unregistered by the obsolete PropEngine object before
* registered again by the new PropEngine object */
d_propEngine.reset(nullptr);
- d_propEngine.reset(new PropEngine(getTheoryEngine(),
- getContext(),
- getUserContext(),
- d_private->getReplayLog(),
- d_replayStream));
+ d_propEngine.reset(
+ new PropEngine(getTheoryEngine(), getContext(), getUserContext()));
d_theoryEngine->setPropEngine(getPropEngine());
}
@@ -5684,6 +4415,9 @@ void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
}
void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver = true; }
+
+bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver; }
+
CVC4::SExpr SmtEngine::getOption(const std::string& key) const
{
NodeManagerScope nms(d_nodeManager);
@@ -5740,12 +4474,6 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
return SExpr::parseAtom(nodeManagerOptions.getOption(key));
}
-void SmtEngine::setReplayStream(ExprStream* replayStream) {
- AlwaysAssert(!d_fullyInited)
- << "Cannot set replay stream once fully initialized";
- d_replayStream = replayStream;
-}
-
bool SmtEngine::getExpressionName(Expr e, std::string& name) const {
return d_private->getExpressionName(e, name);
}
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index fbd92bcf2..37b89cfb7 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -28,7 +28,6 @@
#include "context/cdlist_forward.h"
#include "expr/expr.h"
#include "expr/expr_manager.h"
-#include "expr/expr_stream.h"
#include "options/options.h"
#include "proof/unsat_core.h"
#include "smt/logic_exception.h"
@@ -153,7 +152,9 @@ class CVC4_PUBLIC SmtEngine
*/
bool isFullyInited() { return d_fullyInited; }
- /** Return true if a query() or checkSat() has already been made. */
+ /**
+ * Return true if a checkEntailed() or checkSatisfiability() has been made.
+ */
bool isQueryMade() { return d_queryMade; }
/** Return the user context level. */
@@ -203,6 +204,8 @@ class CVC4_PUBLIC SmtEngine
* --sygus-abduct.
*/
void setIsInternalSubsolver();
+ /** Is this an internal subsolver? */
+ bool isInternalSubsolver() const;
/** set the input name */
void setFilename(std::string filename);
@@ -210,8 +213,8 @@ class CVC4_PUBLIC SmtEngine
std::string getFilename() const;
/**
- * Get the model (only if immediately preceded by a SAT
- * or INVALID query). Only permitted if produce-models is on.
+ * Get the model (only if immediately preceded by a SAT or NOT_ENTAILED
+ * query). Only permitted if produce-models is on.
*/
Model* getModel();
@@ -229,9 +232,9 @@ class CVC4_PUBLIC SmtEngine
/**
* Block the current model values of (at least) the values in exprs.
- * Can be called only if immediately preceded by a SAT or INVALID query. Only
- * permitted if produce-models is on, and the block-models option is set to a
- * mode other than "none".
+ * Can be called only if immediately preceded by a SAT or NOT_ENTAILED query.
+ * Only permitted if produce-models is on, and the block-models option is set
+ * to a mode other than "none".
*
* This adds an assertion to the assertion stack of the form:
* (or (not (= exprs[0] M0)) ... (not (= exprs[n] Mn)))
@@ -309,18 +312,21 @@ class CVC4_PUBLIC SmtEngine
Result assertFormula(const Expr& e, bool inUnsatCore = true);
/**
- * Check validity of an expression with respect to the current set
- * of assertions by asserting the query expression's negation and
- * calling check(). Returns valid, invalid, or unknown result.
+ * Check if a given (set of) expression(s) is entailed with respect to the
+ * current set of assertions. We check this by asserting the negation of
+ * the (big AND over the) given (set of) expression(s).
+ * Returns ENTAILED, NOT_ENTAILED, or ENTAILMENT_UNKNOWN result.
*
* @throw Exception
*/
- Result query(const Expr& assumption = Expr(), bool inUnsatCore = true);
- Result query(const std::vector<Expr>& assumptions, bool inUnsatCore = true);
+ Result checkEntailed(const Expr& assumption = Expr(),
+ bool inUnsatCore = true);
+ Result checkEntailed(const std::vector<Expr>& assumptions,
+ bool inUnsatCore = true);
/**
* Assert a formula (if provided) to the current context and call
- * check(). Returns sat, unsat, or unknown result.
+ * check(). Returns SAT, UNSAT, or SAT_UNKNOWN result.
*
* @throw Exception
*/
@@ -455,9 +461,9 @@ class CVC4_PUBLIC SmtEngine
Expr expandDefinitions(const Expr& e);
/**
- * Get the assigned value of an expr (only if immediately preceded
- * by a SAT or INVALID query). Only permitted if the SmtEngine is
- * set to operate interactively and produce-models is on.
+ * Get the assigned value of an expr (only if immediately preceded by a SAT
+ * or NOT_ENTAILED query). Only permitted if the SmtEngine is set to operate
+ * interactively and produce-models is on.
*
* @throw ModalException, TypeCheckingException, LogicException,
* UnsafeInterruptException
@@ -482,15 +488,15 @@ class CVC4_PUBLIC SmtEngine
/**
* Get the assignment (only if immediately preceded by a SAT or
- * INVALID query). Only permitted if the SmtEngine is set to
+ * NOT_ENTAILED query). Only permitted if the SmtEngine is set to
* operate interactively and produce-assignments is on.
*/
std::vector<std::pair<Expr, Expr> > getAssignment();
/**
- * Get the last proof (only if immediately preceded by an UNSAT
- * or VALID query). Only permitted if CVC4 was built with proof
- * support and produce-proofs is on.
+ * Get the last proof (only if immediately preceded by an UNSAT or ENTAILED
+ * query). Only permitted if CVC4 was built with proof support and
+ * produce-proofs is on.
*
* The Proof object is owned by this SmtEngine until the SmtEngine is
* destroyed.
@@ -623,9 +629,9 @@ class CVC4_PUBLIC SmtEngine
std::vector<std::vector<Expr> >& tvecs);
/**
- * Get an unsatisfiable core (only if immediately preceded by an
- * UNSAT or VALID query). Only permitted if CVC4 was built with
- * unsat-core support and produce-unsat-cores is on.
+ * Get an unsatisfiable core (only if immediately preceded by an UNSAT or
+ * ENTAILED query). Only permitted if CVC4 was built with unsat-core support
+ * and produce-unsat-cores is on.
*/
UnsatCore getUnsatCore();
@@ -713,8 +719,8 @@ class CVC4_PUBLIC SmtEngine
*
* Note that the cumulative timer only ticks away when one of the
* SmtEngine's workhorse functions (things like assertFormula(),
- * query(), checkSat(), and simplify()) are running. Between calls,
- * the timer is still.
+ * checkEntailed(), checkSat(), and simplify()) are running.
+ * Between calls, the timer is still.
*
* When an SmtEngine is first created, it has no time or resource
* limits.
@@ -773,7 +779,10 @@ class CVC4_PUBLIC SmtEngine
/** Flush statistic from this SmtEngine. Safe to use in a signal handler. */
void safeFlushStatistics(int fd) const;
- /** Returns the most recent result of checkSat/query or (set-info :status). */
+ /**
+ * Returns the most recent result of checkSat/checkEntailed or
+ * (set-info :status).
+ */
Result getStatusOfLastCommand() const { return d_status; }
/**
@@ -798,13 +807,6 @@ class CVC4_PUBLIC SmtEngine
void beforeSearch();
/**
- * Expermintal feature: Sets the sequence of decisions.
- * This currently requires very fine grained knowledge about literal
- * translation.
- */
- void setReplayStream(ExprStream* exprStream);
-
- /**
* Get expression name.
*
* Return true if given expressoion has a name in the current context.
@@ -887,7 +889,7 @@ class CVC4_PUBLIC SmtEngine
/**
* Internal method to get an unsatisfiable core (only if immediately preceded
- * by an UNSAT or VALID query). Only permitted if CVC4 was built with
+ * by an UNSAT or ENTAILED query). Only permitted if CVC4 was built with
* unsat-core support and produce-unsat-cores is on. Does not dump the
* command.
*/
@@ -939,12 +941,6 @@ class CVC4_PUBLIC SmtEngine
void finalOptionsAreSet();
/**
- * Apply heuristics settings and other defaults. Done once, at
- * finishInit() time.
- */
- void setDefaults();
-
- /**
* Sets that the problem has been extended. This sets the smt mode of the
* solver to SMT_MODE_ASSERT, and clears the list of assumptions from the
* previous call to checkSatisfiability.
@@ -1019,13 +1015,13 @@ class CVC4_PUBLIC SmtEngine
bool userVisible = true,
const char* dumpTag = "declarations");
- /* Check satisfiability (used for query and check-sat). */
+ /* Check satisfiability (used to check satisfiability and entailment). */
Result checkSatisfiability(const Expr& assumption,
bool inUnsatCore,
- bool isQuery);
+ bool isEntailmentCheck);
Result checkSatisfiability(const std::vector<Expr>& assumptions,
bool inUnsatCore,
- bool isQuery);
+ bool isEntailmentCheck);
/**
* Check that all Expr in formals are of BOUND_VARIABLE kind, where func is
@@ -1135,9 +1131,9 @@ class CVC4_PUBLIC SmtEngine
/**
* The list of assumptions from the previous call to checkSatisfiability.
- * Note that if the last call to checkSatisfiability was a validity check,
- * i.e., a call to query(a1, ..., an), then d_assumptions contains one single
- * assumption ~(a1 AND ... AND an).
+ * Note that if the last call to checkSatisfiability was an entailment check,
+ * i.e., a call to checkEntailed(a1, ..., an), then d_assumptions contains
+ * one single assumption ~(a1 AND ... AND an).
*/
std::vector<Expr> d_assumptions;
@@ -1201,10 +1197,10 @@ class CVC4_PUBLIC SmtEngine
bool d_fullyInited;
/**
- * Whether or not a query() or checkSat() has already been made through
- * this SmtEngine. If true, and incrementalSolving is false, then
- * attempting an additional query() or checkSat() will fail with a
- * ModalException.
+ * Whether or not a checkEntailed() or checkSatisfiability() has already been
+ * made through this SmtEngine. If true, and incrementalSolving is false,
+ * then attempting an additional checkEntailed() or checkSat() will fail with
+ * a ModalException.
*/
bool d_queryMade;
@@ -1226,7 +1222,8 @@ class CVC4_PUBLIC SmtEngine
bool d_globalNegation;
/**
- * Most recent result of last checkSat/query or (set-info :status).
+ * Most recent result of last checkSatisfiability/checkEntailed or
+ * (set-info :status).
*/
Result d_status;
@@ -1247,9 +1244,6 @@ class CVC4_PUBLIC SmtEngine
*/
std::map<std::string, Integer> d_commandVerbosity;
- /** ReplayStream for the solver. */
- ExprStream* d_replayStream;
-
/**
* A private utility class to SmtEngine.
*/
diff --git a/src/theory/arith/arith_utilities.cpp b/src/theory/arith/arith_utilities.cpp
index cbb27197f..cb8524a58 100644
--- a/src/theory/arith/arith_utilities.cpp
+++ b/src/theory/arith/arith_utilities.cpp
@@ -272,6 +272,12 @@ Node arithSubstitute(Node n, std::vector<Node>& vars, std::vector<Node>& subs)
return visited[n];
}
+Node mkBounded(Node l, Node a, Node u)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ return nm->mkNode(AND, nm->mkNode(GEQ, a, l), nm->mkNode(LEQ, a, u));
+}
+
} // namespace arith
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/arith/arith_utilities.h b/src/theory/arith/arith_utilities.h
index f87a908b4..2d466f52f 100644
--- a/src/theory/arith/arith_utilities.h
+++ b/src/theory/arith/arith_utilities.h
@@ -335,6 +335,9 @@ void printRationalApprox(const char* c, Node cr, unsigned prec = 5);
*/
Node arithSubstitute(Node n, std::vector<Node>& vars, std::vector<Node>& subs);
+/** Make the node u >= a ^ a >= l */
+Node mkBounded(Node l, Node a, Node u);
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/nl_lemma_utils.cpp b/src/theory/arith/nl_lemma_utils.cpp
new file mode 100644
index 000000000..e43a77b06
--- /dev/null
+++ b/src/theory/arith/nl_lemma_utils.cpp
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file nl_lemma_utils.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of utilities for the non-linear solver
+ **/
+
+#include "theory/arith/nl_lemma_utils.h"
+
+#include "theory/arith/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+bool SortNlModel::operator()(Node i, Node j)
+{
+ int cv = d_nlm->compare(i, j, d_isConcrete, d_isAbsolute);
+ if (cv == 0)
+ {
+ return i < j;
+ }
+ return d_reverse_order ? cv < 0 : cv > 0;
+}
+
+bool SortNonlinearDegree::operator()(Node i, Node j)
+{
+ unsigned i_count = getDegree(i);
+ unsigned j_count = getDegree(j);
+ return i_count == j_count ? (i < j) : (i_count < j_count ? true : false);
+}
+
+unsigned SortNonlinearDegree::getDegree(Node n) const
+{
+ std::map<Node, unsigned>::const_iterator it = d_mdegree.find(n);
+ Assert(it != d_mdegree.end());
+ return it->second;
+}
+
+Node ArgTrie::add(Node d, const std::vector<Node>& args)
+{
+ ArgTrie* at = this;
+ for (const Node& a : args)
+ {
+ at = &(at->d_children[a]);
+ }
+ if (at->d_data.isNull())
+ {
+ at->d_data = d;
+ }
+ return at->d_data;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl_lemma_utils.h b/src/theory/arith/nl_lemma_utils.h
index 74886a1fb..9ad9f2ca5 100644
--- a/src/theory/arith/nl_lemma_utils.h
+++ b/src/theory/arith/nl_lemma_utils.h
@@ -23,6 +23,8 @@ namespace CVC4 {
namespace theory {
namespace arith {
+class NlModel;
+
/**
* A side effect of adding a lemma in the non-linear solver. This is used
* to specify how the state of the non-linear solver should update. This
@@ -46,6 +48,56 @@ struct NlLemmaSideEffect
std::vector<std::tuple<Node, unsigned, Node> > d_secantPoint;
};
+struct SortNlModel
+{
+ SortNlModel()
+ : d_nlm(nullptr),
+ d_isConcrete(true),
+ d_isAbsolute(false),
+ d_reverse_order(false)
+ {
+ }
+ /** pointer to the model */
+ NlModel* d_nlm;
+ /** are we comparing concrete model values? */
+ bool d_isConcrete;
+ /** are we comparing absolute values? */
+ bool d_isAbsolute;
+ /** are we in reverse order? */
+ bool d_reverse_order;
+ /** the comparison */
+ bool operator()(Node i, Node j);
+};
+
+struct SortNonlinearDegree
+{
+ SortNonlinearDegree(std::map<Node, unsigned>& m) : d_mdegree(m) {}
+ /** pointer to the non-linear extension */
+ std::map<Node, unsigned>& d_mdegree;
+ /** Get the degree of n in d_mdegree */
+ unsigned getDegree(Node n) const;
+ /**
+ * Sorts by degree of the monomials, where lower degree monomials come
+ * first.
+ */
+ bool operator()(Node i, Node j);
+};
+
+/** An argument trie, for computing congruent terms */
+class ArgTrie
+{
+ public:
+ /** children of this node */
+ std::map<Node, ArgTrie> d_children;
+ /** the data of this node */
+ Node d_data;
+ /**
+ * Set d as the data on the node whose path is [args], return either d if
+ * that node has no data, or the data that already occurs there.
+ */
+ Node add(Node d, const std::vector<Node>& args);
+};
+
} // namespace arith
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/arith/nonlinear_extension.cpp b/src/theory/arith/nonlinear_extension.cpp
index f11d55855..61a8b18b0 100644
--- a/src/theory/arith/nonlinear_extension.cpp
+++ b/src/theory/arith/nonlinear_extension.cpp
@@ -113,49 +113,6 @@ void debugPrintBound(const char* c, Node coeff, Node x, Kind type, Node rhs) {
Trace(c) << t << " " << type << " " << rhs;
}
-struct SortNlModel
-{
- SortNlModel()
- : d_nlm(nullptr),
- d_isConcrete(true),
- d_isAbsolute(false),
- d_reverse_order(false)
- {
- }
- /** pointer to the model */
- NlModel* d_nlm;
- /** are we comparing concrete model values? */
- bool d_isConcrete;
- /** are we comparing absolute values? */
- bool d_isAbsolute;
- /** are we in reverse order? */
- bool d_reverse_order;
- /** the comparison */
- bool operator()(Node i, Node j) {
- int cv = d_nlm->compare(i, j, d_isConcrete, d_isAbsolute);
- if (cv == 0) {
- return i < j;
- }
- return d_reverse_order ? cv < 0 : cv > 0;
- }
-};
-struct SortNonlinearDegree
-{
- SortNonlinearDegree(NodeMultiset& m) : d_mdegree(m) {}
- /** pointer to the non-linear extension */
- NodeMultiset& d_mdegree;
- /**
- * Sorts by degree of the monomials, where lower degree monomials come
- * first.
- */
- bool operator()(Node i, Node j)
- {
- unsigned i_count = getCount(d_mdegree, i);
- unsigned j_count = getCount(d_mdegree, j);
- return i_count == j_count ? (i < j) : (i_count < j_count ? true : false);
- }
-};
-
bool hasNewMonomials(Node n, const std::vector<Node>& existing) {
std::set<Node> visited;
@@ -189,6 +146,7 @@ NonlinearExtension::NonlinearExtension(TheoryArith& containing,
d_ee(ee),
d_needsLastCall(false),
d_model(containing.getSatContext()),
+ d_trSlv(d_model),
d_builtModel(containing.getSatContext(), false)
{
d_true = NodeManager::currentNM()->mkConst(true);
@@ -200,13 +158,6 @@ NonlinearExtension::NonlinearExtension(TheoryArith& containing,
d_order_points.push_back(d_neg_one);
d_order_points.push_back(d_zero);
d_order_points.push_back(d_one);
- d_taylor_real_fv = NodeManager::currentNM()->mkBoundVar(
- "x", NodeManager::currentNM()->realType());
- d_taylor_real_fv_base = NodeManager::currentNM()->mkBoundVar(
- "a", NodeManager::currentNM()->realType());
- d_taylor_real_fv_base_rem = NodeManager::currentNM()->mkBoundVar(
- "b", NodeManager::currentNM()->realType());
- d_taylor_degree = options::nlExtTfTaylorDegree();
}
NonlinearExtension::~NonlinearExtension() {}
@@ -509,13 +460,6 @@ Node NonlinearExtension::mkValidPhase(Node a, Node pi) {
NodeManager::currentNM()->mkNode(MULT, mkRationalNode(-1), pi), a, pi);
}
-Node NonlinearExtension::mkBounded( Node l, Node a, Node u ) {
- return NodeManager::currentNM()->mkNode(
- AND,
- NodeManager::currentNM()->mkNode(GEQ, a, l),
- NodeManager::currentNM()->mkNode(LEQ, a, u));
-}
-
Node NonlinearExtension::mkMonomialRemFactor(
Node n, const NodeMultiset& n_exp_rem) const {
std::vector<Node> children;
@@ -566,13 +510,7 @@ void NonlinearExtension::sendLemmas(const std::vector<Node>& out,
void NonlinearExtension::processSideEffect(const NlLemmaSideEffect& se)
{
- for (const std::tuple<Node, unsigned, Node>& sp : se.d_secantPoint)
- {
- Node tf = std::get<0>(sp);
- unsigned d = std::get<1>(sp);
- Node c = std::get<2>(sp);
- d_secant_points[tf][d].push_back(c);
- }
+ d_trSlv.processSideEffect(se);
}
unsigned NonlinearExtension::filterLemma(Node lem, std::vector<Node>& out)
@@ -779,90 +717,18 @@ bool NonlinearExtension::checkModel(const std::vector<Node>& assertions,
// get the presubstitution
Trace("nl-ext-cm-debug") << " apply pre-substitution..." << std::endl;
- std::vector<Node> pvars;
- std::vector<Node> psubs;
- for (std::pair<const Node, Node>& tb : d_trMaster)
- {
- pvars.push_back(tb.first);
- psubs.push_back(tb.second);
- }
- // initialize representation of assertions
- std::vector<Node> passertions;
- for (const Node& a : assertions)
- {
- Node pa = a;
- if (!pvars.empty())
- {
- pa = arithSubstitute(pa, pvars, psubs);
- pa = Rewriter::rewrite(pa);
- }
- if (!pa.isConst() || !pa.getConst<bool>())
- {
- Trace("nl-ext-cm-assert") << "- assert : " << pa << std::endl;
- passertions.push_back(pa);
- }
- }
+ std::vector<Node> passertions = assertions;
- // get model bounds for all transcendental functions
- Trace("nl-ext-cm") << "----- Get bounds for transcendental functions..."
- << std::endl;
- for (std::pair<const Kind, std::vector<Node> >& tfs : d_funcMap)
+ // preprocess the assertions with the trancendental solver
+ if (!d_trSlv.preprocessAssertionsCheckModel(passertions))
{
- Kind k = tfs.first;
- for (const Node& tf : tfs.second)
- {
- Trace("nl-ext-cm") << "- Term: " << tf << std::endl;
- bool success = true;
- // tf is Figure 3 : tf( x )
- Node bl;
- Node bu;
- if (k == PI)
- {
- bl = d_pi_bound[0];
- bu = d_pi_bound[1];
- }
- else
- {
- std::pair<Node, Node> bounds = getTfModelBounds(tf, d_taylor_degree);
- bl = bounds.first;
- bu = bounds.second;
- if (bl != bu)
- {
- d_model.setUsedApproximate();
- }
- }
- if (!bl.isNull() && !bu.isNull())
- {
- // for each function in the congruence classe
- for (const Node& ctf : d_funcCongClass[tf])
- {
- // each term in congruence classes should be master terms
- Assert(d_trSlaves.find(ctf) != d_trSlaves.end());
- // we set the bounds for each slave of tf
- for (const Node& stf : d_trSlaves[ctf])
- {
- Trace("nl-ext-cm") << "...bound for " << stf << " : [" << bl << ", "
- << bu << "]" << std::endl;
- success = d_model.addCheckModelBound(stf, bl, bu);
- }
- }
- }
- else
- {
- Trace("nl-ext-cm") << "...no bound for " << tf << std::endl;
- }
- if (!success)
- {
- // a bound was conflicting
- Trace("nl-ext-cm") << "...failed to set bound for " << tf << std::endl;
- Trace("nl-ext-cm") << "-----" << std::endl;
- return false;
- }
- }
+ return false;
}
+
Trace("nl-ext-cm") << "-----" << std::endl;
- bool ret = d_model.checkModel(
- passertions, false_asserts, d_taylor_degree, lemmas, gs);
+ unsigned tdegree = d_trSlv.getTaylorDegree();
+ bool ret =
+ d_model.checkModel(passertions, false_asserts, tdegree, lemmas, gs);
return ret;
}
@@ -882,33 +748,6 @@ std::vector<Node> NonlinearExtension::checkSplitZero() {
return lemmas;
}
-/** An argument trie, for computing congruent terms */
-class ArgTrie
-{
- public:
- /** children of this node */
- std::map<Node, ArgTrie> d_children;
- /** the data of this node */
- Node d_data;
- /**
- * Set d as the data on the node whose path is [args], return either d if
- * that node has no data, or the data that already occurs there.
- */
- Node add(Node d, const std::vector<Node>& args)
- {
- ArgTrie* at = this;
- for (const Node& a : args)
- {
- at = &(at->d_children[a]);
- }
- if (at->d_data.isNull())
- {
- at->d_data = d;
- }
- return at->d_data;
- }
-};
-
int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
const std::vector<Node>& false_asserts,
const std::vector<Node>& xts,
@@ -926,18 +765,8 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
d_ci.clear();
d_ci_exp.clear();
d_ci_max.clear();
- d_funcCongClass.clear();
- d_funcMap.clear();
- d_tf_region.clear();
-
- std::vector<Node> lemmas;
- NodeManager* nm = NodeManager::currentNM();
Trace("nl-ext-mv") << "Extended terms : " << std::endl;
- // register the extended function terms
- std::map< Node, Node > mvarg_to_term;
- std::vector<Node> trNeedsMaster;
- bool needPi = false;
// for computing congruence
std::map<Kind, ArgTrie> argTrie;
for (unsigned i = 0, xsize = xts.size(); i < xsize; i++)
@@ -947,47 +776,6 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
d_model.computeAbstractModelValue(a);
d_model.printModelValue("nl-ext-mv", a);
Kind ak = a.getKind();
- bool consider = true;
- // if is an unpurified application of SINE, or it is a transcendental
- // applied to a trancendental, purify.
- if (isTranscendentalKind(ak))
- {
- // if we've already computed master for a
- if (d_trMaster.find(a) != d_trMaster.end())
- {
- // a master has at least one slave
- consider = (d_trSlaves.find(a) != d_trSlaves.end());
- }
- else
- {
- if (ak == SINE)
- {
- // always not a master
- consider = false;
- }
- else
- {
- for (const Node& ac : a)
- {
- if (isTranscendentalKind(ac.getKind()))
- {
- consider = false;
- break;
- }
- }
- }
- if (!consider)
- {
- // wait to assign a master below
- trNeedsMaster.push_back(a);
- }
- else
- {
- d_trMaster[a] = a;
- d_trSlaves[a].insert(a);
- }
- }
- }
if (ak == NONLINEAR_MULT)
{
d_ms.push_back( a );
@@ -1008,126 +796,19 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
}
// mark processed if has a "one" factor (will look at reduced monomial)?
}
- else if (a.getNumChildren() > 0)
- {
- if (ak == SINE)
- {
- needPi = true;
- }
- // if we didn't indicate that it should be purified above
- if( consider ){
- std::vector<Node> repList;
- for (const Node& ac : a)
- {
- Node r = d_model.computeConcreteModelValue(ac);
- repList.push_back(r);
- }
- Node aa = argTrie[ak].add(a, repList);
- if (aa != a)
- {
- // apply congruence to pairs of terms that are disequal and congruent
- Assert(aa.getNumChildren() == a.getNumChildren());
- Node mvaa = d_model.computeAbstractModelValue(a);
- Node mvaaa = d_model.computeAbstractModelValue(aa);
- if (mvaa != mvaaa)
- {
- std::vector<Node> exp;
- for (unsigned j = 0, size = a.getNumChildren(); j < size; j++)
- {
- exp.push_back(a[j].eqNode(aa[j]));
- }
- Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
- Node cong_lemma = nm->mkNode(OR, expn.negate(), a.eqNode(aa));
- lemmas.push_back( cong_lemma );
- }
- }
- else
- {
- // new representative of congruence class
- d_funcMap[ak].push_back(a);
- }
- // add to congruence class
- d_funcCongClass[aa].push_back(a);
- }
- }
- else if (ak == PI)
- {
- Assert(consider);
- needPi = true;
- d_funcMap[ak].push_back(a);
- d_funcCongClass[a].push_back(a);
- }
- else
- {
- Assert(false);
- }
- }
- // initialize pi if necessary
- if (needPi && d_pi.isNull())
- {
- mkPi();
- getCurrentPiBounds(lemmas);
}
+ // initialize the trancendental function solver
+ std::vector<Node> lemmas;
+ d_trSlv.initLastCall(assertions, false_asserts, xts, lemmas, lemsPp);
+
+ // process lemmas that may have been generated by the transcendental solver
filterLemmas(lemmas, lems);
- if (!lems.empty())
+ if (!lems.empty() || !lemsPp.empty())
{
Trace("nl-ext") << " ...finished with " << lems.size()
<< " new lemmas during registration." << std::endl;
- return lems.size();
- }
-
- // process SINE phase shifting
- for (const Node& a : trNeedsMaster)
- {
- // should not have processed this already
- Assert(d_trMaster.find(a) == d_trMaster.end());
- Kind k = a.getKind();
- Assert(k == SINE || k == EXPONENTIAL);
- Node y =
- nm->mkSkolem("y", nm->realType(), "phase shifted trigonometric arg");
- Node new_a = nm->mkNode(k, y);
- d_trSlaves[new_a].insert(new_a);
- d_trSlaves[new_a].insert(a);
- d_trMaster[a] = new_a;
- d_trMaster[new_a] = new_a;
- Node lem;
- if (k == SINE)
- {
- Trace("nl-ext-tf") << "Basis sine : " << new_a << " for " << a
- << std::endl;
- Assert(!d_pi.isNull());
- Node shift = nm->mkSkolem("s", nm->integerType(), "number of shifts");
- // TODO : do not introduce shift here, instead needs model-based
- // refinement for constant shifts (cvc4-projects #1284)
- lem = nm->mkNode(
- AND,
- mkValidPhase(y, d_pi),
- nm->mkNode(
- ITE,
- mkValidPhase(a[0], d_pi),
- a[0].eqNode(y),
- a[0].eqNode(nm->mkNode(
- PLUS,
- y,
- nm->mkNode(MULT, nm->mkConst(Rational(2)), shift, d_pi)))),
- new_a.eqNode(a));
- }
- else
- {
- // do both equalities to ensure that new_a becomes a preregistered term
- lem = nm->mkNode(AND, a.eqNode(new_a), a[0].eqNode(y));
- }
- // note we must do preprocess on this lemma
- Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : purify : " << lem
- << std::endl;
- lemsPp.push_back(lem);
- }
- if (!lemsPp.empty())
- {
- Trace("nl-ext") << " ...finished with " << lemsPp.size()
- << " new lemmas SINE phase shifting." << std::endl;
- return lemsPp.size();
+ return lems.size() + lemsPp.size();
}
Trace("nl-ext") << "We have " << d_ms.size() << " monomials." << std::endl;
@@ -1148,25 +829,6 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
d_model.computeAbstractModelValue(v);
d_model.printModelValue("nl-ext-mv", v);
}
- if (Trace.isOn("nl-ext-mv"))
- {
- Trace("nl-ext-mv") << "Arguments of trancendental functions : "
- << std::endl;
- for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
- {
- Kind k = tfl.first;
- if (k == SINE || k == EXPONENTIAL)
- {
- for (const Node& tf : tfl.second)
- {
- Node v = tf[0];
- d_model.computeConcreteModelValue(v);
- d_model.computeAbstractModelValue(v);
- d_model.printModelValue("nl-ext-mv", v);
- }
- }
- }
- }
//----------------------------------- possibly split on zero
if (options::nlExtSplitZero()) {
@@ -1182,7 +844,7 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
}
//-----------------------------------initial lemmas for transcendental functions
- lemmas = checkTranscendentalInitialRefine();
+ lemmas = d_trSlv.checkTranscendentalInitialRefine();
filterLemmas(lemmas, lems);
if (!lems.empty())
{
@@ -1202,7 +864,7 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
}
//-----------------------------------monotonicity of transdental functions
- lemmas = checkTranscendentalMonotonic();
+ lemmas = d_trSlv.checkTranscendentalMonotonic();
filterLemmas(lemmas, lems);
if (!lems.empty())
{
@@ -1313,7 +975,7 @@ int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
}
if (options::nlExtTfTangentPlanes())
{
- lemmas = checkTranscendentalTangentPlanes(lemSE);
+ lemmas = d_trSlv.checkTranscendentalTangentPlanes(lemSE);
filterLemmas(lemmas, wlems);
}
Trace("nl-ext") << " ...finished with " << wlems.size() << " waiting lemmas."
@@ -1543,12 +1205,12 @@ bool NonlinearExtension::modelBasedRefinement(
// we are incomplete
if (options::nlExtIncPrecision() && d_model.usedApproximate())
{
- d_taylor_degree++;
+ d_trSlv.incrementTaylorDegree();
needsRecheck = true;
// increase precision for PI?
// Difficult since Taylor series is very slow to converge
- Trace("nl-ext") << "...increment Taylor degree to " << d_taylor_degree
- << std::endl;
+ Trace("nl-ext") << "...increment Taylor degree to "
+ << d_trSlv.getTaylorDegree() << std::endl;
}
else
{
@@ -1660,36 +1322,6 @@ void NonlinearExtension::assignOrderIds(std::vector<Node>& vars,
}
}
-void NonlinearExtension::mkPi(){
- if( d_pi.isNull() ){
- d_pi = NodeManager::currentNM()->mkNullaryOperator(
- NodeManager::currentNM()->realType(), PI);
- d_pi_2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(
- MULT,
- d_pi,
- NodeManager::currentNM()->mkConst(Rational(1) / Rational(2))));
- d_pi_neg_2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(
- MULT,
- d_pi,
- NodeManager::currentNM()->mkConst(Rational(-1) / Rational(2))));
- d_pi_neg = Rewriter::rewrite(NodeManager::currentNM()->mkNode(
- MULT, d_pi, NodeManager::currentNM()->mkConst(Rational(-1))));
- //initialize bounds
- d_pi_bound[0] =
- NodeManager::currentNM()->mkConst(Rational(103993) / Rational(33102));
- d_pi_bound[1] =
- NodeManager::currentNM()->mkConst(Rational(104348) / Rational(33215));
- }
-}
-
-void NonlinearExtension::getCurrentPiBounds( std::vector< Node >& lemmas ) {
- Node pi_lem = NodeManager::currentNM()->mkNode(
- AND,
- NodeManager::currentNM()->mkNode(GEQ, d_pi, d_pi_bound[0]),
- NodeManager::currentNM()->mkNode(LEQ, d_pi, d_pi_bound[1]));
- lemmas.push_back( pi_lem );
-}
-
bool NonlinearExtension::getApproximateSqrt(Node c,
Node& l,
Node& u,
@@ -2807,1098 +2439,6 @@ std::vector<Node> NonlinearExtension::checkMonomialInferResBounds() {
}
return lemmas;
}
-
-std::vector<Node> NonlinearExtension::checkTranscendentalInitialRefine() {
- std::vector< Node > lemmas;
- Trace("nl-ext") << "Get initial refinement lemmas for transcendental functions..." << std::endl;
- for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
- {
- Kind k = tfl.first;
- for (const Node& t : tfl.second)
- {
- //initial refinements
- if( d_tf_initial_refine.find( t )==d_tf_initial_refine.end() ){
- d_tf_initial_refine[t] = true;
- Node lem;
- if (k == SINE)
- {
- Node symn = NodeManager::currentNM()->mkNode(
- SINE, NodeManager::currentNM()->mkNode(MULT, d_neg_one, t[0]));
- symn = Rewriter::rewrite( symn );
- // Can assume it is its own master since phase is split over 0,
- // hence -pi <= t[0] <= pi implies -pi <= -t[0] <= pi.
- d_trMaster[symn] = symn;
- d_trSlaves[symn].insert(symn);
- Assert(d_trSlaves.find(t) != d_trSlaves.end());
- std::vector< Node > children;
-
- lem = NodeManager::currentNM()->mkNode(
- AND,
- // bounds
- NodeManager::currentNM()->mkNode(
- AND,
- NodeManager::currentNM()->mkNode(LEQ, t, d_one),
- NodeManager::currentNM()->mkNode(GEQ, t, d_neg_one)),
- // symmetry
- NodeManager::currentNM()->mkNode(PLUS, t, symn).eqNode(d_zero),
- // sign
- NodeManager::currentNM()->mkNode(
- EQUAL,
- NodeManager::currentNM()->mkNode(LT, t[0], d_zero),
- NodeManager::currentNM()->mkNode(LT, t, d_zero)),
- // zero val
- NodeManager::currentNM()->mkNode(
- EQUAL,
- NodeManager::currentNM()->mkNode(GT, t[0], d_zero),
- NodeManager::currentNM()->mkNode(GT, t, d_zero)));
- lem = NodeManager::currentNM()->mkNode(
- AND,
- lem,
- // zero tangent
- NodeManager::currentNM()->mkNode(
- AND,
- NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(GT, t[0], d_zero),
- NodeManager::currentNM()->mkNode(LT, t, t[0])),
- NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(LT, t[0], d_zero),
- NodeManager::currentNM()->mkNode(GT, t, t[0]))),
- // pi tangent
- NodeManager::currentNM()->mkNode(
- AND,
- NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(LT, t[0], d_pi),
- NodeManager::currentNM()->mkNode(
- LT,
- t,
- NodeManager::currentNM()->mkNode(MINUS, d_pi, t[0]))),
- NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(GT, t[0], d_pi_neg),
- NodeManager::currentNM()->mkNode(
- GT,
- t,
- NodeManager::currentNM()->mkNode(
- MINUS, d_pi_neg, t[0])))));
- }
- else if (k == EXPONENTIAL)
- {
- // ( exp(x) > 0 ) ^ ( x=0 <=> exp( x ) = 1 ) ^ ( x < 0 <=> exp( x ) <
- // 1 ) ^ ( x <= 0 V exp( x ) > x + 1 )
- lem = NodeManager::currentNM()->mkNode(
- AND,
- NodeManager::currentNM()->mkNode(GT, t, d_zero),
- NodeManager::currentNM()->mkNode(
- EQUAL, t[0].eqNode(d_zero), t.eqNode(d_one)),
- NodeManager::currentNM()->mkNode(
- EQUAL,
- NodeManager::currentNM()->mkNode(LT, t[0], d_zero),
- NodeManager::currentNM()->mkNode(LT, t, d_one)),
- NodeManager::currentNM()->mkNode(
- OR,
- NodeManager::currentNM()->mkNode(LEQ, t[0], d_zero),
- NodeManager::currentNM()->mkNode(
- GT,
- t,
- NodeManager::currentNM()->mkNode(PLUS, t[0], d_one))));
- }
- if( !lem.isNull() ){
- lemmas.push_back( lem );
- }
- }
- }
- }
-
- return lemmas;
-}
-
-std::vector<Node> NonlinearExtension::checkTranscendentalMonotonic() {
- std::vector< Node > lemmas;
- Trace("nl-ext") << "Get monotonicity lemmas for transcendental functions..." << std::endl;
-
- //sort arguments of all transcendentals
- std::map< Kind, std::vector< Node > > sorted_tf_args;
- std::map< Kind, std::map< Node, Node > > tf_arg_to_term;
-
- for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
- {
- Kind k = tfl.first;
- if (k == EXPONENTIAL || k == SINE)
- {
- for (const Node& tf : tfl.second)
- {
- Node a = tf[0];
- Node mvaa = d_model.computeAbstractModelValue(a);
- if (mvaa.isConst())
- {
- Trace("nl-ext-tf-mono-debug") << "...tf term : " << a << std::endl;
- sorted_tf_args[k].push_back(a);
- tf_arg_to_term[k][a] = tf;
- }
- }
- }
- }
-
- SortNlModel smv;
- smv.d_nlm = &d_model;
- //sort by concrete values
- smv.d_isConcrete = true;
- smv.d_reverse_order = true;
- for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
- {
- Kind k = tfl.first;
- if( !sorted_tf_args[k].empty() ){
- std::sort( sorted_tf_args[k].begin(), sorted_tf_args[k].end(), smv );
- Trace("nl-ext-tf-mono") << "Sorted transcendental function list for " << k << " : " << std::endl;
- for (unsigned i = 0; i < sorted_tf_args[k].size(); i++)
- {
- Node targ = sorted_tf_args[k][i];
- Node mvatarg = d_model.computeAbstractModelValue(targ);
- Trace("nl-ext-tf-mono")
- << " " << targ << " -> " << mvatarg << std::endl;
- Node t = tf_arg_to_term[k][targ];
- Node mvat = d_model.computeAbstractModelValue(t);
- Trace("nl-ext-tf-mono") << " f-val : " << mvat << std::endl;
- }
- std::vector< Node > mpoints;
- std::vector< Node > mpoints_vals;
- if (k == SINE)
- {
- mpoints.push_back( d_pi );
- mpoints.push_back( d_pi_2 );
- mpoints.push_back(d_zero);
- mpoints.push_back( d_pi_neg_2 );
- mpoints.push_back( d_pi_neg );
- }
- else if (k == EXPONENTIAL)
- {
- mpoints.push_back( Node::null() );
- }
- if( !mpoints.empty() ){
- //get model values for points
- for( unsigned i=0; i<mpoints.size(); i++ ){
- Node mpv;
- if( !mpoints[i].isNull() ){
- mpv = d_model.computeAbstractModelValue(mpoints[i]);
- Assert(mpv.isConst());
- }
- mpoints_vals.push_back( mpv );
- }
-
- unsigned mdir_index = 0;
- int monotonic_dir = -1;
- Node mono_bounds[2];
- Node targ, targval, t, tval;
- for (unsigned i = 0, size = sorted_tf_args[k].size(); i < size; i++)
- {
- Node sarg = sorted_tf_args[k][i];
- Node sargval = d_model.computeAbstractModelValue(sarg);
- Assert(sargval.isConst());
- Node s = tf_arg_to_term[k][ sarg ];
- Node sval = d_model.computeAbstractModelValue(s);
- Assert(sval.isConst());
-
- //increment to the proper monotonicity region
- bool increment = true;
- while (increment && mdir_index < mpoints.size())
- {
- increment = false;
- if( mpoints[mdir_index].isNull() ){
- increment = true;
- }else{
- Node pval = mpoints_vals[mdir_index];
- Assert(pval.isConst());
- if( sargval.getConst<Rational>() < pval.getConst<Rational>() ){
- increment = true;
- Trace("nl-ext-tf-mono") << "...increment at " << sarg << " since model value is less than " << mpoints[mdir_index] << std::endl;
- }
- }
- if( increment ){
- tval = Node::null();
- mono_bounds[1] = mpoints[mdir_index];
- mdir_index++;
- monotonic_dir = regionToMonotonicityDir(k, mdir_index);
- if (mdir_index < mpoints.size())
- {
- mono_bounds[0] = mpoints[mdir_index];
- }else{
- mono_bounds[0] = Node::null();
- }
- }
- }
- // store the concavity region
- d_tf_region[s] = mdir_index;
- Trace("nl-ext-concavity") << "Transcendental function " << s
- << " is in region #" << mdir_index;
- Trace("nl-ext-concavity") << ", arg model value = " << sargval
- << std::endl;
-
- if( !tval.isNull() ){
- Node mono_lem;
- if( monotonic_dir==1 && sval.getConst<Rational>() > tval.getConst<Rational>() ){
- mono_lem = NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(GEQ, targ, sarg),
- NodeManager::currentNM()->mkNode(GEQ, t, s));
- }else if( monotonic_dir==-1 && sval.getConst<Rational>() < tval.getConst<Rational>() ){
- mono_lem = NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(LEQ, targ, sarg),
- NodeManager::currentNM()->mkNode(LEQ, t, s));
- }
- if( !mono_lem.isNull() ){
- if( !mono_bounds[0].isNull() ){
- Assert(!mono_bounds[1].isNull());
- mono_lem = NodeManager::currentNM()->mkNode(
- IMPLIES,
- NodeManager::currentNM()->mkNode(
- AND,
- mkBounded(mono_bounds[0], targ, mono_bounds[1]),
- mkBounded(mono_bounds[0], sarg, mono_bounds[1])),
- mono_lem);
- }
- Trace("nl-ext-tf-mono") << "Monotonicity lemma : " << mono_lem << std::endl;
- lemmas.push_back( mono_lem );
- }
- }
- // store the previous values
- targ = sarg;
- targval = sargval;
- t = s;
- tval = sval;
- }
- }
- }
- }
- return lemmas;
-}
-
-std::vector<Node> NonlinearExtension::checkTranscendentalTangentPlanes(
- std::map<Node, NlLemmaSideEffect>& lemSE)
-{
- std::vector<Node> lemmas;
- Trace("nl-ext") << "Get tangent plane lemmas for transcendental functions..."
- << std::endl;
- // this implements Figure 3 of "Satisfiaility Modulo Transcendental Functions
- // via Incremental Linearization" by Cimatti et al
- for (std::pair<const Kind, std::vector<Node> >& tfs : d_funcMap)
- {
- Kind k = tfs.first;
- if (k == PI)
- {
- // We do not use Taylor approximation for PI currently.
- // This is because the convergence is extremely slow, and hence an
- // initial approximation is superior.
- continue;
- }
- Trace("nl-ext-tftp-debug2") << "Taylor variables: " << std::endl;
- Trace("nl-ext-tftp-debug2")
- << " taylor_real_fv : " << d_taylor_real_fv << std::endl;
- Trace("nl-ext-tftp-debug2")
- << " taylor_real_fv_base : " << d_taylor_real_fv_base << std::endl;
- Trace("nl-ext-tftp-debug2")
- << " taylor_real_fv_base_rem : " << d_taylor_real_fv_base_rem
- << std::endl;
- Trace("nl-ext-tftp-debug2") << std::endl;
-
- // we substitute into the Taylor sum P_{n,f(0)}( x )
-
- for (const Node& tf : tfs.second)
- {
- // tf is Figure 3 : tf( x )
- Trace("nl-ext-tftp") << "Compute tangent planes " << tf << std::endl;
- // go until max degree is reached, or we don't meet bound criteria
- for (unsigned d = 1; d <= d_taylor_degree; d++)
- {
- Trace("nl-ext-tftp") << "- run at degree " << d << "..." << std::endl;
- unsigned prev = lemmas.size();
- if (checkTfTangentPlanesFun(tf, d, lemmas, lemSE))
- {
- Trace("nl-ext-tftp")
- << "...fail, #lemmas = " << (lemmas.size() - prev) << std::endl;
- break;
- }
- else
- {
- Trace("nl-ext-tftp") << "...success" << std::endl;
- }
- }
- }
- }
-
- return lemmas;
-}
-
-bool NonlinearExtension::checkTfTangentPlanesFun(
- Node tf,
- unsigned d,
- std::vector<Node>& lemmas,
- std::map<Node, NlLemmaSideEffect>& lemSE)
-{
- NodeManager* nm = NodeManager::currentNM();
- Kind k = tf.getKind();
- // this should only be run on master applications
- Assert(d_trSlaves.find(tf) != d_trSlaves.end());
-
- // Figure 3 : c
- Node c = d_model.computeAbstractModelValue(tf[0]);
- int csign = c.getConst<Rational>().sgn();
- if (csign == 0)
- {
- // no secant/tangent plane is necessary
- return true;
- }
- Assert(csign == 1 || csign == -1);
-
- // Figure 3: P_l, P_u
- // mapped to for signs of c
- std::map<int, Node> poly_approx_bounds[2];
- std::vector<Node> pbounds;
- getPolynomialApproximationBoundForArg(k, c, d, pbounds);
- poly_approx_bounds[0][1] = pbounds[0];
- poly_approx_bounds[0][-1] = pbounds[1];
- poly_approx_bounds[1][1] = pbounds[2];
- poly_approx_bounds[1][-1] = pbounds[3];
-
- // Figure 3 : v
- Node v = d_model.computeAbstractModelValue(tf);
-
- // check value of tf
- Trace("nl-ext-tftp-debug") << "Process tangent plane refinement for " << tf
- << ", degree " << d << "..." << std::endl;
- Trace("nl-ext-tftp-debug") << " value in model : " << v << std::endl;
- Trace("nl-ext-tftp-debug") << " arg value in model : " << c << std::endl;
-
- std::vector<Node> taylor_vars;
- taylor_vars.push_back(d_taylor_real_fv);
-
- // compute the concavity
- int region = -1;
- std::unordered_map<Node, int, NodeHashFunction>::iterator itr =
- d_tf_region.find(tf);
- if (itr != d_tf_region.end())
- {
- region = itr->second;
- Trace("nl-ext-tftp-debug") << " region is : " << region << std::endl;
- }
- // Figure 3 : conc
- int concavity = regionToConcavity(k, itr->second);
- Trace("nl-ext-tftp-debug") << " concavity is : " << concavity << std::endl;
- if (concavity == 0)
- {
- // no secant/tangent plane is necessary
- return true;
- }
- // bounds for which we are this concavity
- // Figure 3: < l, u >
- Node bounds[2];
- if (k == SINE)
- {
- bounds[0] = regionToLowerBound(k, region);
- Assert(!bounds[0].isNull());
- bounds[1] = regionToUpperBound(k, region);
- Assert(!bounds[1].isNull());
- }
-
- // Figure 3: P
- Node poly_approx;
-
- // compute whether this is a tangent refinement or a secant refinement
- bool is_tangent = false;
- bool is_secant = false;
- std::pair<Node, Node> mvb = getTfModelBounds(tf, d);
- for (unsigned r = 0; r < 2; r++)
- {
- Node pab = poly_approx_bounds[r][csign];
- Node v_pab = r == 0 ? mvb.first : mvb.second;
- if (!v_pab.isNull())
- {
- Trace("nl-ext-tftp-debug2") << "...model value of " << pab << " is "
- << v_pab << std::endl;
-
- Assert(v_pab.isConst());
- Node comp = nm->mkNode(r == 0 ? LT : GT, v, v_pab);
- Trace("nl-ext-tftp-debug2") << "...compare : " << comp << std::endl;
- Node compr = Rewriter::rewrite(comp);
- Trace("nl-ext-tftp-debug2") << "...got : " << compr << std::endl;
- if (compr == d_true)
- {
- // beyond the bounds
- if (r == 0)
- {
- poly_approx = poly_approx_bounds[r][csign];
- is_tangent = concavity == 1;
- is_secant = concavity == -1;
- }
- else
- {
- poly_approx = poly_approx_bounds[r][csign];
- is_tangent = concavity == -1;
- is_secant = concavity == 1;
- }
- if (Trace.isOn("nl-ext-tftp"))
- {
- Trace("nl-ext-tftp") << "*** Outside boundary point (";
- Trace("nl-ext-tftp") << (r == 0 ? "low" : "high") << ") ";
- printRationalApprox("nl-ext-tftp", v_pab);
- Trace("nl-ext-tftp") << ", will refine..." << std::endl;
- Trace("nl-ext-tftp") << " poly_approx = " << poly_approx
- << std::endl;
- Trace("nl-ext-tftp") << " is_tangent = " << is_tangent
- << std::endl;
- Trace("nl-ext-tftp") << " is_secant = " << is_secant << std::endl;
- }
- break;
- }
- else
- {
- Trace("nl-ext-tftp") << " ...within " << (r == 0 ? "low" : "high")
- << " bound : ";
- printRationalApprox("nl-ext-tftp", v_pab);
- Trace("nl-ext-tftp") << std::endl;
- }
- }
- }
-
- // Figure 3: P( c )
- Node poly_approx_c;
- if (is_tangent || is_secant)
- {
- Assert(!poly_approx.isNull());
- std::vector<Node> taylor_subs;
- taylor_subs.push_back(c);
- Assert(taylor_vars.size() == taylor_subs.size());
- poly_approx_c = poly_approx.substitute(taylor_vars.begin(),
- taylor_vars.end(),
- taylor_subs.begin(),
- taylor_subs.end());
- Trace("nl-ext-tftp-debug2") << "...poly approximation at c is "
- << poly_approx_c << std::endl;
- }
- else
- {
- // we may want to continue getting better bounds
- return false;
- }
-
- if (is_tangent)
- {
- // compute tangent plane
- // Figure 3: T( x )
- // We use zero slope tangent planes, since the concavity of the Taylor
- // approximation cannot be easily established.
- Node tplane = poly_approx_c;
-
- Node lem = nm->mkNode(concavity == 1 ? GEQ : LEQ, tf, tplane);
- std::vector<Node> antec;
- int mdir = regionToMonotonicityDir(k, region);
- for (unsigned i = 0; i < 2; i++)
- {
- // Tangent plane is valid in the interval [c,u) if the slope of the
- // function matches its concavity, and is valid in (l, c] otherwise.
- Node use_bound = (mdir == concavity) == (i == 0) ? c : bounds[i];
- if (!use_bound.isNull())
- {
- Node ant = nm->mkNode(i == 0 ? GEQ : LEQ, tf[0], use_bound);
- antec.push_back(ant);
- }
- }
- if (!antec.empty())
- {
- Node antec_n = antec.size() == 1 ? antec[0] : nm->mkNode(AND, antec);
- lem = nm->mkNode(IMPLIES, antec_n, lem);
- }
- Trace("nl-ext-tftp-debug2")
- << "*** Tangent plane lemma (pre-rewrite): " << lem << std::endl;
- lem = Rewriter::rewrite(lem);
- Trace("nl-ext-tftp-lemma") << "*** Tangent plane lemma : " << lem
- << std::endl;
- Assert(d_model.computeAbstractModelValue(lem) == d_false);
- // Figure 3 : line 9
- lemmas.push_back(lem);
- }
- else if (is_secant)
- {
- // bounds are the minimum and maximum previous secant points
- // should not repeat secant points: secant lemmas should suffice to
- // rule out previous assignment
- Assert(std::find(
- d_secant_points[tf][d].begin(), d_secant_points[tf][d].end(), c)
- == d_secant_points[tf][d].end());
- // Insert into the (temporary) vector. We do not update this vector
- // until we are sure this secant plane lemma has been processed. We do
- // this by mapping the lemma to a side effect below.
- std::vector<Node> spoints = d_secant_points[tf][d];
- spoints.push_back(c);
-
- // sort
- SortNlModel smv;
- smv.d_nlm = &d_model;
- smv.d_isConcrete = true;
- std::sort(spoints.begin(), spoints.end(), smv);
- // get the resulting index of c
- unsigned index =
- std::find(spoints.begin(), spoints.end(), c) - spoints.begin();
- // bounds are the next closest upper/lower bound values
- if (index > 0)
- {
- bounds[0] = spoints[index - 1];
- }
- else
- {
- // otherwise, we use the lower boundary point for this concavity
- // region
- if (k == SINE)
- {
- Assert(!bounds[0].isNull());
- }
- else if (k == EXPONENTIAL)
- {
- // pick c-1
- bounds[0] = Rewriter::rewrite(nm->mkNode(MINUS, c, d_one));
- }
- }
- if (index < spoints.size() - 1)
- {
- bounds[1] = spoints[index + 1];
- }
- else
- {
- // otherwise, we use the upper boundary point for this concavity
- // region
- if (k == SINE)
- {
- Assert(!bounds[1].isNull());
- }
- else if (k == EXPONENTIAL)
- {
- // pick c+1
- bounds[1] = Rewriter::rewrite(nm->mkNode(PLUS, c, d_one));
- }
- }
- Trace("nl-ext-tftp-debug2") << "...secant bounds are : " << bounds[0]
- << " ... " << bounds[1] << std::endl;
-
- // the secant plane may be conjunction of 1-2 guarded inequalities
- std::vector<Node> lemmaConj;
- for (unsigned s = 0; s < 2; s++)
- {
- // compute secant plane
- Assert(!poly_approx.isNull());
- Assert(!bounds[s].isNull());
- // take the model value of l or u (since may contain PI)
- Node b = d_model.computeAbstractModelValue(bounds[s]);
- Trace("nl-ext-tftp-debug2") << "...model value of bound " << bounds[s]
- << " is " << b << std::endl;
- Assert(b.isConst());
- if (c != b)
- {
- // Figure 3 : P(l), P(u), for s = 0,1
- Node poly_approx_b;
- std::vector<Node> taylor_subs;
- taylor_subs.push_back(b);
- Assert(taylor_vars.size() == taylor_subs.size());
- poly_approx_b = poly_approx.substitute(taylor_vars.begin(),
- taylor_vars.end(),
- taylor_subs.begin(),
- taylor_subs.end());
- // Figure 3: S_l( x ), S_u( x ) for s = 0,1
- Node splane;
- Node rcoeff_n = Rewriter::rewrite(nm->mkNode(MINUS, b, c));
- Assert(rcoeff_n.isConst());
- Rational rcoeff = rcoeff_n.getConst<Rational>();
- Assert(rcoeff.sgn() != 0);
- poly_approx_b = Rewriter::rewrite(poly_approx_b);
- poly_approx_c = Rewriter::rewrite(poly_approx_c);
- splane = nm->mkNode(
- PLUS,
- poly_approx_b,
- nm->mkNode(MULT,
- nm->mkNode(MINUS, poly_approx_b, poly_approx_c),
- nm->mkConst(Rational(1) / rcoeff),
- nm->mkNode(MINUS, tf[0], b)));
-
- Node lem = nm->mkNode(concavity == 1 ? LEQ : GEQ, tf, splane);
- // With respect to Figure 3, this is slightly different.
- // In particular, we chose b to be the model value of bounds[s],
- // which is a constant although bounds[s] may not be (e.g. if it
- // contains PI).
- // To ensure that c...b does not cross an inflection point,
- // we guard with the symbolic version of bounds[s].
- // This leads to lemmas e.g. of this form:
- // ( c <= x <= PI/2 ) => ( sin(x) < ( P( b ) - P( c ) )*( x -
- // b ) + P( b ) )
- // where b = (PI/2)^M, the current value of PI/2 in the model.
- // This is sound since we are guarded by the symbolic
- // representation of PI/2.
- Node antec_n =
- nm->mkNode(AND,
- nm->mkNode(GEQ, tf[0], s == 0 ? bounds[s] : c),
- nm->mkNode(LEQ, tf[0], s == 0 ? c : bounds[s]));
- lem = nm->mkNode(IMPLIES, antec_n, lem);
- Trace("nl-ext-tftp-debug2")
- << "*** Secant plane lemma (pre-rewrite) : " << lem << std::endl;
- lem = Rewriter::rewrite(lem);
- Trace("nl-ext-tftp-lemma") << "*** Secant plane lemma : " << lem
- << std::endl;
- lemmaConj.push_back(lem);
- Assert(d_model.computeAbstractModelValue(lem) == d_false);
- }
- }
- // Figure 3 : line 22
- Assert(!lemmaConj.empty());
- Node lem =
- lemmaConj.size() == 1 ? lemmaConj[0] : nm->mkNode(AND, lemmaConj);
- lemmas.push_back(lem);
- // The side effect says that if lem is added, then we should add the
- // secant point c for (tf,d).
- lemSE[lem].d_secantPoint.push_back(std::make_tuple(tf, d, c));
- }
- return true;
-}
-
-int NonlinearExtension::regionToMonotonicityDir(Kind k, int region)
-{
- if (k == EXPONENTIAL)
- {
- if (region == 1)
- {
- return 1;
- }
- }
- else if (k == SINE)
- {
- if (region == 1 || region == 4)
- {
- return -1;
- }
- else if (region == 2 || region == 3)
- {
- return 1;
- }
- }
- return 0;
-}
-
-int NonlinearExtension::regionToConcavity(Kind k, int region)
-{
- if (k == EXPONENTIAL)
- {
- if (region == 1)
- {
- return 1;
- }
- }
- else if (k == SINE)
- {
- if (region == 1 || region == 2)
- {
- return -1;
- }
- else if (region == 3 || region == 4)
- {
- return 1;
- }
- }
- return 0;
-}
-
-Node NonlinearExtension::regionToLowerBound(Kind k, int region)
-{
- if (k == SINE)
- {
- if (region == 1)
- {
- return d_pi_2;
- }
- else if (region == 2)
- {
- return d_zero;
- }
- else if (region == 3)
- {
- return d_pi_neg_2;
- }
- else if (region == 4)
- {
- return d_pi_neg;
- }
- }
- return Node::null();
-}
-
-Node NonlinearExtension::regionToUpperBound(Kind k, int region)
-{
- if (k == SINE)
- {
- if (region == 1)
- {
- return d_pi;
- }
- else if (region == 2)
- {
- return d_pi_2;
- }
- else if (region == 3)
- {
- return d_zero;
- }
- else if (region == 4)
- {
- return d_pi_neg_2;
- }
- }
- return Node::null();
-}
-
-Node NonlinearExtension::getDerivative(Node n, Node x)
-{
- Assert(x.isVar());
- // only handle the cases of the taylor expansion of d
- if (n.getKind() == EXPONENTIAL)
- {
- if (n[0] == x)
- {
- return n;
- }
- }
- else if (n.getKind() == SINE)
- {
- if (n[0] == x)
- {
- Node na = NodeManager::currentNM()->mkNode(MINUS, d_pi_2, n[0]);
- Node ret = NodeManager::currentNM()->mkNode(SINE, na);
- ret = Rewriter::rewrite(ret);
- return ret;
- }
- }
- else if (n.getKind() == PLUS)
- {
- std::vector<Node> dchildren;
- for (unsigned i = 0; i < n.getNumChildren(); i++)
- {
- // PLUS is flattened in rewriter, recursion depth is bounded by 1
- Node dc = getDerivative(n[i], x);
- if (dc.isNull())
- {
- return dc;
- }else{
- dchildren.push_back(dc);
- }
- }
- return NodeManager::currentNM()->mkNode(PLUS, dchildren);
- }
- else if (n.getKind() == MULT)
- {
- Assert(n[0].isConst());
- Node dc = getDerivative(n[1], x);
- if (!dc.isNull())
- {
- return NodeManager::currentNM()->mkNode(MULT, n[0], dc);
- }
- }
- else if (n.getKind() == NONLINEAR_MULT)
- {
- unsigned xcount = 0;
- std::vector<Node> children;
- unsigned xindex = 0;
- for (unsigned i = 0, size = n.getNumChildren(); i < size; i++)
- {
- if (n[i] == x)
- {
- xcount++;
- xindex = i;
- }
- children.push_back(n[i]);
- }
- if (xcount == 0)
- {
- return d_zero;
- }
- else
- {
- children[xindex] = NodeManager::currentNM()->mkConst(Rational(xcount));
- }
- return NodeManager::currentNM()->mkNode(MULT, children);
- }
- else if (n.isVar())
- {
- return n == x ? d_one : d_zero;
- }
- else if (n.isConst())
- {
- return d_zero;
- }
- Trace("nl-ext-debug") << "No derivative computed for " << n;
- Trace("nl-ext-debug") << " for d/d{" << x << "}" << std::endl;
- return Node::null();
-}
-
-std::pair<Node, Node> NonlinearExtension::getTaylor(Node fa, unsigned n)
-{
- Assert(n > 0);
- Node fac; // what term we cache for fa
- if (fa[0] == d_zero)
- {
- // optimization : simpler to compute (x-fa[0])^n if we are centered around 0
- fac = fa;
- }
- else
- {
- // otherwise we use a standard factor a in (x-a)^n
- fac = NodeManager::currentNM()->mkNode(fa.getKind(), d_taylor_real_fv_base);
- }
- Node taylor_rem;
- Node taylor_sum;
- // check if we have already computed this Taylor series
- std::unordered_map<unsigned, Node>::iterator itt = d_taylor_sum[fac].find(n);
- if (itt == d_taylor_sum[fac].end())
- {
- Node i_exp_base;
- if (fa[0] == d_zero)
- {
- i_exp_base = d_taylor_real_fv;
- }
- else
- {
- i_exp_base = Rewriter::rewrite(NodeManager::currentNM()->mkNode(
- MINUS, d_taylor_real_fv, d_taylor_real_fv_base));
- }
- Node i_derv = fac;
- Node i_fact = d_one;
- Node i_exp = d_one;
- int i_derv_status = 0;
- unsigned counter = 0;
- std::vector<Node> sum;
- do
- {
- counter++;
- if (fa.getKind() == EXPONENTIAL)
- {
- // unchanged
- }
- else if (fa.getKind() == SINE)
- {
- if (i_derv_status % 2 == 1)
- {
- Node arg = NodeManager::currentNM()->mkNode(
- PLUS, d_pi_2, d_taylor_real_fv_base);
- i_derv = NodeManager::currentNM()->mkNode(SINE, arg);
- }
- else
- {
- i_derv = fa;
- }
- if (i_derv_status >= 2)
- {
- i_derv = NodeManager::currentNM()->mkNode(MINUS, d_zero, i_derv);
- }
- i_derv = Rewriter::rewrite(i_derv);
- i_derv_status = i_derv_status == 3 ? 0 : i_derv_status + 1;
- }
- if (counter == (n + 1))
- {
- TNode x = d_taylor_real_fv_base;
- i_derv = i_derv.substitute(x, d_taylor_real_fv_base_rem);
- }
- Node curr = NodeManager::currentNM()->mkNode(
- MULT,
- NodeManager::currentNM()->mkNode(DIVISION, i_derv, i_fact),
- i_exp);
- if (counter == (n + 1))
- {
- taylor_rem = curr;
- }
- else
- {
- sum.push_back(curr);
- i_fact = Rewriter::rewrite(NodeManager::currentNM()->mkNode(
- MULT,
- NodeManager::currentNM()->mkConst(Rational(counter)),
- i_fact));
- i_exp = Rewriter::rewrite(
- NodeManager::currentNM()->mkNode(MULT, i_exp_base, i_exp));
- }
- } while (counter <= n);
- taylor_sum =
- sum.size() == 1 ? sum[0] : NodeManager::currentNM()->mkNode(PLUS, sum);
-
- if (fac[0] != d_taylor_real_fv_base)
- {
- TNode x = d_taylor_real_fv_base;
- taylor_sum = taylor_sum.substitute(x, fac[0]);
- }
-
- // cache
- d_taylor_sum[fac][n] = taylor_sum;
- d_taylor_rem[fac][n] = taylor_rem;
- }
- else
- {
- taylor_sum = itt->second;
- Assert(d_taylor_rem[fac].find(n) != d_taylor_rem[fac].end());
- taylor_rem = d_taylor_rem[fac][n];
- }
-
- // must substitute for the argument if we were using a different lookup
- if (fa[0] != fac[0])
- {
- TNode x = d_taylor_real_fv_base;
- taylor_sum = taylor_sum.substitute(x, fa[0]);
- }
- return std::pair<Node, Node>(taylor_sum, taylor_rem);
-}
-
-void NonlinearExtension::getPolynomialApproximationBounds(
- Kind k, unsigned d, std::vector<Node>& pbounds)
-{
- if (d_poly_bounds[k][d].empty())
- {
- NodeManager* nm = NodeManager::currentNM();
- Node tft = nm->mkNode(k, d_zero);
- // n is the Taylor degree we are currently considering
- unsigned n = 2 * d;
- // n must be even
- std::pair<Node, Node> taylor = getTaylor(tft, n);
- Trace("nl-ext-tftp-debug2") << "Taylor for " << k
- << " is : " << taylor.first << std::endl;
- Node taylor_sum = Rewriter::rewrite(taylor.first);
- Trace("nl-ext-tftp-debug2") << "Taylor for " << k
- << " is (post-rewrite) : " << taylor_sum
- << std::endl;
- Assert(taylor.second.getKind() == MULT);
- Assert(taylor.second.getNumChildren() == 2);
- Assert(taylor.second[0].getKind() == DIVISION);
- Trace("nl-ext-tftp-debug2") << "Taylor remainder for " << k << " is "
- << taylor.second << std::endl;
- // ru is x^{n+1}/(n+1)!
- Node ru = nm->mkNode(DIVISION, taylor.second[1], taylor.second[0][1]);
- ru = Rewriter::rewrite(ru);
- Trace("nl-ext-tftp-debug2")
- << "Taylor remainder factor is (post-rewrite) : " << ru << std::endl;
- if (k == EXPONENTIAL)
- {
- pbounds.push_back(taylor_sum);
- pbounds.push_back(taylor_sum);
- pbounds.push_back(Rewriter::rewrite(
- nm->mkNode(MULT, taylor_sum, nm->mkNode(PLUS, d_one, ru))));
- pbounds.push_back(Rewriter::rewrite(nm->mkNode(PLUS, taylor_sum, ru)));
- }
- else
- {
- Assert(k == SINE);
- Node l = Rewriter::rewrite(nm->mkNode(MINUS, taylor_sum, ru));
- Node u = Rewriter::rewrite(nm->mkNode(PLUS, taylor_sum, ru));
- pbounds.push_back(l);
- pbounds.push_back(l);
- pbounds.push_back(u);
- pbounds.push_back(u);
- }
- Trace("nl-ext-tf-tplanes") << "Polynomial approximation for " << k
- << " is: " << std::endl;
- Trace("nl-ext-tf-tplanes") << " Lower (pos): " << pbounds[0] << std::endl;
- Trace("nl-ext-tf-tplanes") << " Upper (pos): " << pbounds[2] << std::endl;
- Trace("nl-ext-tf-tplanes") << " Lower (neg): " << pbounds[1] << std::endl;
- Trace("nl-ext-tf-tplanes") << " Upper (neg): " << pbounds[3] << std::endl;
- d_poly_bounds[k][d].insert(
- d_poly_bounds[k][d].end(), pbounds.begin(), pbounds.end());
- }
- else
- {
- pbounds.insert(
- pbounds.end(), d_poly_bounds[k][d].begin(), d_poly_bounds[k][d].end());
- }
-}
-
-void NonlinearExtension::getPolynomialApproximationBoundForArg(
- Kind k, Node c, unsigned d, std::vector<Node>& pbounds)
-{
- getPolynomialApproximationBounds(k, d, pbounds);
- Assert(c.isConst());
- if (k == EXPONENTIAL && c.getConst<Rational>().sgn() == 1)
- {
- NodeManager* nm = NodeManager::currentNM();
- Node tft = nm->mkNode(k, d_zero);
- bool success = false;
- unsigned ds = d;
- TNode ttrf = d_taylor_real_fv;
- TNode tc = c;
- do
- {
- success = true;
- unsigned n = 2 * ds;
- std::pair<Node, Node> taylor = getTaylor(tft, n);
- // check that 1-c^{n+1}/(n+1)! > 0
- Node ru = nm->mkNode(DIVISION, taylor.second[1], taylor.second[0][1]);
- Node rus = ru.substitute(ttrf, tc);
- rus = Rewriter::rewrite(rus);
- Assert(rus.isConst());
- if (rus.getConst<Rational>() > d_one.getConst<Rational>())
- {
- success = false;
- ds = ds + 1;
- }
- } while (!success);
- if (ds > d)
- {
- Trace("nl-ext-exp-taylor")
- << "*** Increase Taylor bound to " << ds << " > " << d << " for ("
- << k << " " << c << ")" << std::endl;
- // must use sound upper bound
- std::vector<Node> pboundss;
- getPolynomialApproximationBounds(k, ds, pboundss);
- pbounds[2] = pboundss[2];
- }
- }
-}
-
-std::pair<Node, Node> NonlinearExtension::getTfModelBounds(Node tf, unsigned d)
-{
- // compute the model value of the argument
- Node c = d_model.computeAbstractModelValue(tf[0]);
- Assert(c.isConst());
- int csign = c.getConst<Rational>().sgn();
- Kind k = tf.getKind();
- if (csign == 0)
- {
- // at zero, its trivial
- if (k == SINE)
- {
- return std::pair<Node, Node>(d_zero, d_zero);
- }
- Assert(k == EXPONENTIAL);
- return std::pair<Node, Node>(d_one, d_one);
- }
- bool isNeg = csign == -1;
-
- std::vector<Node> pbounds;
- getPolynomialApproximationBoundForArg(k, c, d, pbounds);
-
- std::vector<Node> bounds;
- TNode tfv = d_taylor_real_fv;
- TNode tfs = tf[0];
- for (unsigned d2 = 0; d2 < 2; d2++)
- {
- int index = d2 == 0 ? (isNeg ? 1 : 0) : (isNeg ? 3 : 2);
- Node pab = pbounds[index];
- if (!pab.isNull())
- {
- // { x -> tf[0] }
- pab = pab.substitute(tfv, tfs);
- pab = Rewriter::rewrite(pab);
- Node v_pab = d_model.computeAbstractModelValue(pab);
- bounds.push_back(v_pab);
- }
- else
- {
- bounds.push_back(Node::null());
- }
- }
- return std::pair<Node, Node>(bounds[0], bounds[1]);
-}
} // namespace arith
} // namespace theory
diff --git a/src/theory/arith/nonlinear_extension.h b/src/theory/arith/nonlinear_extension.h
index 19810730f..bfc713b12 100644
--- a/src/theory/arith/nonlinear_extension.h
+++ b/src/theory/arith/nonlinear_extension.h
@@ -37,6 +37,7 @@
#include "theory/arith/nl_lemma_utils.h"
#include "theory/arith/nl_model.h"
#include "theory/arith/theory_arith.h"
+#include "theory/arith/transcendental_solver.h"
#include "theory/uf/equality_engine.h"
namespace CVC4 {
@@ -253,7 +254,6 @@ class NonlinearExtension {
static Node mkLit(Node a, Node b, int status, bool isAbsolute = false);
static Node mkAbs(Node a);
static Node mkValidPhase(Node a, Node pi);
- static Node mkBounded( Node l, Node a, Node u );
Node mkMonomialRemFactor(Node n, const NodeMultiset& n_exp_rem) const;
//---------------------------------------end term utilities
@@ -449,21 +449,6 @@ class NonlinearExtension {
Node d_two;
Node d_true;
Node d_false;
- /** PI
- *
- * Note that PI is a (symbolic, non-constant) nullary operator. This is
- * because its value cannot be computed exactly. We constraint PI to concrete
- * lower and upper bounds stored in d_pi_bound below.
- */
- Node d_pi;
- /** PI/2 */
- Node d_pi_2;
- /** -PI/2 */
- Node d_pi_neg_2;
- /** -PI */
- Node d_pi_neg;
- /** the concrete lower and upper bounds for PI */
- Node d_pi_bound[2];
// The theory of arithmetic containing this extension.
TheoryArith& d_containing;
@@ -488,6 +473,12 @@ class NonlinearExtension {
* and for establishing when we are able to answer "SAT".
*/
NlModel d_model;
+ /** The transcendental extension object
+ *
+ * This is the subsolver responsible for running the procedure for
+ * transcendental functions.
+ */
+ TranscendentalSolver d_trSlv;
/**
* The lemmas we computed during collectModelInfo. We store two vectors of
* lemmas to be sent out on the output channel of TheoryArith. The first
@@ -509,27 +500,6 @@ class NonlinearExtension {
std::map<Node, unsigned> d_order_vars;
std::vector<Node> d_order_points;
- //transcendental functions
- /**
- * Some transcendental functions f(t) are "purified", e.g. we add
- * t = y ^ f(t) = f(y) where y is a fresh variable. Those that are not
- * purified we call "master terms".
- *
- * The maps below maintain a master/slave relationship over
- * transcendental functions (SINE, EXPONENTIAL, PI), where above
- * f(y) is the master of itself and of f(t).
- *
- * This is used for ensuring that the argument y of SINE we process is on the
- * interval [-pi .. pi], and that exponentials are not applied to arguments
- * that contain transcendental functions.
- */
- std::map<Node, Node> d_trMaster;
- std::map<Node, std::unordered_set<Node, NodeHashFunction>> d_trSlaves;
- /** The transcendental functions we have done initial refinements on */
- std::map< Node, bool > d_tf_initial_refine;
-
- void mkPi();
- void getCurrentPiBounds( std::vector< Node >& lemmas );
private:
//per last-call effort check
@@ -552,25 +522,6 @@ class NonlinearExtension {
std::map<Node, std::map<Node, std::map<Node, Node> > > d_ci_exp;
std::map<Node, std::map<Node, std::map<Node, bool> > > d_ci_max;
- /**
- * Maps representives of a congruence class to the members of that class.
- *
- * In detail, a congruence class is a set of terms of the form
- * { f(t1), ..., f(tn) }
- * such that t1 = ... = tn in the current context. We choose an arbitrary
- * term among these to be the repesentative of this congruence class.
- *
- * Moreover, notice we compute congruence classes only over terms that
- * are transcendental function applications that are "master terms",
- * see d_trMaster/d_trSlave.
- */
- std::map<Node, std::vector<Node> > d_funcCongClass;
- /**
- * A list of all functions for each kind in { EXPONENTIAL, SINE, POW, PI }
- * that are representives of their congruence class.
- */
- std::map<Kind, std::vector<Node> > d_funcMap;
-
// factor skolems
std::map< Node, Node > d_factor_skolem;
Node getFactorSkolem( Node n, std::vector< Node >& lemmas );
@@ -578,96 +529,6 @@ class NonlinearExtension {
// tangent plane bounds
std::map< Node, std::map< Node, Node > > d_tangent_val_bound[4];
- /** secant points (sorted list) for transcendental functions
- *
- * This is used for tangent plane refinements for
- * transcendental functions. This is the set
- * "get-previous-secant-points" in "Satisfiability
- * Modulo Transcendental Functions via Incremental
- * Linearization" by Cimatti et al., CADE 2017, for
- * each transcendental function application. We store this set for each
- * Taylor degree.
- */
- std::unordered_map<Node,
- std::map<unsigned, std::vector<Node> >,
- NodeHashFunction>
- d_secant_points;
-
- /** get Taylor series of degree n for function fa centered around point fa[0].
- *
- * Return value is ( P_{n,f(a)}( x ), R_{n+1,f(a)}( x ) ) where
- * the first part of the pair is the Taylor series expansion :
- * P_{n,f(a)}( x ) = sum_{i=0}^n (f^i( a )/i!)*(x-a)^i
- * and the second part of the pair is the Taylor series remainder :
- * R_{n+1,f(a),b}( x ) = (f^{n+1}( b )/(n+1)!)*(x-a)^{n+1}
- *
- * The above values are cached for each (f,n) for a fixed variable "a".
- * To compute the Taylor series for fa, we compute the Taylor series
- * for ( fa.getKind(), n ) then substitute { a -> fa[0] } if fa[0]!=0.
- * We compute P_{n,f(0)}( x )/R_{n+1,f(0),b}( x ) for ( fa.getKind(), n )
- * if fa[0]=0.
- * In the latter case, note we compute the exponential x^{n+1}
- * instead of (x-a)^{n+1}, which can be done faster.
- */
- std::pair<Node, Node> getTaylor(Node fa, unsigned n);
-
- /** internal variables used for constructing (cached) versions of the Taylor
- * series above.
- */
- Node d_taylor_real_fv; // x above
- Node d_taylor_real_fv_base; // a above
- Node d_taylor_real_fv_base_rem; // b above
-
- /** cache of sum and remainder terms for getTaylor */
- std::unordered_map<Node, std::unordered_map<unsigned, Node>, NodeHashFunction>
- d_taylor_sum;
- std::unordered_map<Node, std::unordered_map<unsigned, Node>, NodeHashFunction>
- d_taylor_rem;
- /** taylor degree
- *
- * Indicates that the degree of the polynomials in the Taylor approximation of
- * all transcendental functions is 2*d_taylor_degree. This value is set
- * initially to options::nlExtTfTaylorDegree() and may be incremented
- * if the option options::nlExtTfIncPrecision() is enabled.
- */
- unsigned d_taylor_degree;
- /** polynomial approximation bounds
- *
- * This adds P_l+[x], P_l-[x], P_u+[x], P_u-[x] to pbounds, where x is
- * d_taylor_real_fv. These are polynomial approximations of the Taylor series
- * of <k>( 0 ) for degree 2*d where k is SINE or EXPONENTIAL.
- * These correspond to P_l and P_u from Figure 3 of Cimatti et al., CADE 2017,
- * for positive/negative (+/-) values of the argument of <k>( 0 ).
- *
- * Notice that for certain bounds (e.g. upper bounds for exponential), the
- * Taylor approximation for a fixed degree is only sound up to a given
- * upper bound on the argument. To obtain sound lower/upper bounds for a
- * given <k>( c ), use the function below.
- */
- void getPolynomialApproximationBounds(Kind k,
- unsigned d,
- std::vector<Node>& pbounds);
- /** polynomial approximation bounds
- *
- * This computes polynomial approximations P_l+[x], P_l-[x], P_u+[x], P_u-[x]
- * that are sound (lower, upper) bounds for <k>( c ). Notice that these
- * polynomials may depend on c. In particular, for P_u+[x] for <k>( c ) where
- * c>0, we return the P_u+[x] from the function above for the minimum degree
- * d' >= d such that (1-c^{2*d'+1}/(2*d'+1)!) is positive.
- */
- void getPolynomialApproximationBoundForArg(Kind k,
- Node c,
- unsigned d,
- std::vector<Node>& pbounds);
- /** cache of the above function */
- std::map<Kind, std::map<unsigned, std::vector<Node> > > d_poly_bounds;
- /** get transcendental function model bounds
- *
- * This returns the current lower and upper bounds of transcendental
- * function application tf based on Taylor of degree 2*d, which is dependent
- * on the model value of its argument.
- */
- std::pair<Node, Node> getTfModelBounds(Node tf, unsigned d);
/** get approximate sqrt
*
* This approximates the square root of positive constant c. If this method
@@ -680,70 +541,6 @@ class NonlinearExtension {
*/
bool getApproximateSqrt(Node c, Node& l, Node& u, unsigned iter = 15) const;
- /** concavity region for transcendental functions
- *
- * This stores an integer that identifies an interval in
- * which the current model value for an argument of an
- * application of a transcendental function resides.
- *
- * For exp( x ):
- * region #1 is -infty < x < infty
- * For sin( x ):
- * region #0 is pi < x < infty (this is an invalid region)
- * region #1 is pi/2 < x <= pi
- * region #2 is 0 < x <= pi/2
- * region #3 is -pi/2 < x <= 0
- * region #4 is -pi < x <= -pi/2
- * region #5 is -infty < x <= -pi (this is an invalid region)
- * All regions not listed above, as well as regions 0 and 5
- * for SINE are "invalid". We only process applications
- * of transcendental functions whose arguments have model
- * values that reside in valid regions.
- */
- std::unordered_map<Node, int, NodeHashFunction> d_tf_region;
- /** get monotonicity direction
- *
- * Returns whether the slope is positive (+1) or negative(-1)
- * in region of transcendental function with kind k.
- * Returns 0 if region is invalid.
- */
- int regionToMonotonicityDir(Kind k, int region);
- /** get concavity
- *
- * Returns whether we are concave (+1) or convex (-1)
- * in region of transcendental function with kind k,
- * where region is defined above.
- * Returns 0 if region is invalid.
- */
- int regionToConcavity(Kind k, int region);
- /** region to lower bound
- *
- * Returns the term corresponding to the lower
- * bound of the region of transcendental function
- * with kind k. Returns Node::null if the region
- * is invalid, or there is no lower bound for the
- * region.
- */
- Node regionToLowerBound(Kind k, int region);
- /** region to upper bound
- *
- * Returns the term corresponding to the upper
- * bound of the region of transcendental function
- * with kind k. Returns Node::null if the region
- * is invalid, or there is no upper bound for the
- * region.
- */
- Node regionToUpperBound(Kind k, int region);
- /** get derivative
- *
- * Returns d/dx n. Supports cases of n
- * for transcendental functions applied to x,
- * multiplication, addition, constants and variables.
- * Returns Node::null() if derivative is an
- * unhandled case.
- */
- Node getDerivative(Node n, Node x);
-
private:
//-------------------------------------------- lemma schemas
/** check split zero
@@ -873,122 +670,6 @@ class NonlinearExtension {
*/
std::vector<Node> checkTangentPlanes();
- /** check transcendental initial refine
- *
- * Returns a set of valid theory lemmas, based on
- * simple facts about transcendental functions.
- * This mostly follows the initial axioms described in
- * Section 4 of "Satisfiability
- * Modulo Transcendental Functions via Incremental
- * Linearization" by Cimatti et al., CADE 2017.
- *
- * Examples:
- *
- * sin( x ) = -sin( -x )
- * ( PI > x > 0 ) => 0 < sin( x ) < 1
- * exp( x )>0
- * x<0 => exp( x )<1
- */
- std::vector<Node> checkTranscendentalInitialRefine();
-
- /** check transcendental monotonic
- *
- * Returns a set of valid theory lemmas, based on a
- * lemma scheme that ensures that applications
- * of transcendental functions respect monotonicity.
- *
- * Examples:
- *
- * x > y => exp( x ) > exp( y )
- * PI/2 > x > y > 0 => sin( x ) > sin( y )
- * PI > x > y > PI/2 => sin( x ) < sin( y )
- */
- std::vector<Node> checkTranscendentalMonotonic();
-
- /** check transcendental tangent planes
- *
- * Returns a set of valid theory lemmas, based on
- * computing an "incremental linearization" of
- * transcendental functions based on the model values
- * of transcendental functions and their arguments.
- * It is based on Figure 3 of "Satisfiability
- * Modulo Transcendental Functions via Incremental
- * Linearization" by Cimatti et al., CADE 2017.
- * This schema is not terminating in general.
- * It is not enabled by default, and can
- * be enabled by --nl-ext-tf-tplanes.
- *
- * Example:
- *
- * Assume we have a term sin(y) where M( y ) = 1 where M is the current model.
- * Note that:
- * sin(1) ~= .841471
- *
- * The Taylor series and remainder of sin(y) of degree 7 is
- * P_{7,sin(0)}( x ) = x + (-1/6)*x^3 + (1/20)*x^5
- * R_{7,sin(0),b}( x ) = (-1/5040)*x^7
- *
- * This gives us lower and upper bounds :
- * P_u( x ) = P_{7,sin(0)}( x ) + R_{7,sin(0),b}( x )
- * ...where note P_u( 1 ) = 4243/5040 ~= .841865
- * P_l( x ) = P_{7,sin(0)}( x ) - R_{7,sin(0),b}( x )
- * ...where note P_l( 1 ) = 4241/5040 ~= .841468
- *
- * Assume that M( sin(y) ) > P_u( 1 ).
- * Since the concavity of sine in the region 0 < x < PI/2 is -1,
- * we add a tangent plane refinement.
- * The tangent plane at the point 1 in P_u is
- * given by the formula:
- * T( x ) = P_u( 1 ) + ((d/dx)(P_u(x)))( 1 )*( x - 1 )
- * We add the lemma:
- * ( 0 < y < PI/2 ) => sin( y ) <= T( y )
- * which is:
- * ( 0 < y < PI/2 ) => sin( y ) <= (391/720)*(y - 2737/1506)
- *
- * Assume that M( sin(y) ) < P_u( 1 ).
- * Since the concavity of sine in the region 0 < x < PI/2 is -1,
- * we add a secant plane refinement for some constants ( l, u )
- * such that 0 <= l < M( y ) < u <= PI/2. Assume we choose
- * l = 0 and u = M( PI/2 ) = 150517/47912.
- * The secant planes at point 1 for P_l
- * are given by the formulas:
- * S_l( x ) = (x-l)*(P_l( l )-P_l(c))/(l-1) + P_l( l )
- * S_u( x ) = (x-u)*(P_l( u )-P_l(c))/(u-1) + P_l( u )
- * We add the lemmas:
- * ( 0 < y < 1 ) => sin( y ) >= S_l( y )
- * ( 1 < y < PI/2 ) => sin( y ) >= S_u( y )
- * which are:
- * ( 0 < y < 1 ) => (sin y) >= 4251/5040*y
- * ( 1 < y < PI/2 ) => (sin y) >= c1*(y+c2)
- * where c1, c2 are rationals (for brevity, omitted here)
- * such that c1 ~= .277 and c2 ~= 2.032.
- *
- * The argument lemSE is the "side effect" of the lemmas in the return
- * value of this function (for details, see checkLastCall).
- */
- std::vector<Node> checkTranscendentalTangentPlanes(
- std::map<Node, NlLemmaSideEffect>& lemSE);
- /** check transcendental function refinement for tf
- *
- * This method is called by the above method for each "master"
- * transcendental function application that occurs in an assertion in the
- * current context. For example, an application like sin(t) is not a master
- * if we have introduced the constraints:
- * t=y+2*pi*n ^ -pi <= y <= pi ^ sin(t) = sin(y).
- * See d_trMaster/d_trSlaves for more detail.
- *
- * This runs Figure 3 of Cimatti et al., CADE 2017 for transcendental
- * function application tf for Taylor degree d. It may add a secant or
- * tangent plane lemma to lems and its side effect (if one exists)
- * to lemSE.
- *
- * It returns false if the bounds are not precise enough to add a
- * secant or tangent plane lemma.
- */
- bool checkTfTangentPlanesFun(Node tf,
- unsigned d,
- std::vector<Node>& lems,
- std::map<Node, NlLemmaSideEffect>& lemSE);
//-------------------------------------------- end lemma schemas
}; /* class NonlinearExtension */
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index 8986e6894..2c748f188 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -19,6 +19,7 @@
#include "options/smt_options.h"
#include "smt/smt_statistics_registry.h"
+#include "theory/arith/arith_rewriter.h"
#include "theory/arith/infer_bounds.h"
#include "theory/arith/theory_arith_private.h"
#include "theory/ext_theory.h"
@@ -53,6 +54,11 @@ TheoryArith::~TheoryArith(){
delete d_internal;
}
+std::unique_ptr<TheoryRewriter> TheoryArith::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new ArithRewriter());
+}
+
void TheoryArith::preRegisterTerm(TNode n){
d_internal->preRegisterTerm(n);
}
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index b39ab961f..92892d2ae 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -51,6 +51,8 @@ public:
Valuation valuation, const LogicInfo& logicInfo);
virtual ~TheoryArith();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
/**
* Does non-context dependent setup for a node connected to a theory.
*/
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index 4e2a5bba1..bed59baf5 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -3943,15 +3943,38 @@ Node TheoryArithPrivate::branchIntegerVariable(ArithVar x) const {
TNode var = d_partialModel.asNode(x);
Integer floor_d = d.floor();
- //Node eq = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL, var, mkRationalNode(floor_d+1)));
- //Node diseq = eq.notNode();
-
- Node ub = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::LEQ, var, mkRationalNode(floor_d)));
- Node lb = ub.notNode();
-
+ Node lem;
+ NodeManager* nm = NodeManager::currentNM();
+ if (options::brabTest())
+ {
+ Trace("integers") << "branch-round-and-bound enabled" << endl;
+ Integer ceil_d = d.ceiling();
+ Rational f = r - floor_d;
+ // Multiply by -1 to get abs value.
+ Rational c = (r - ceil_d) * (-1);
+ Integer nearest = (c > f) ? floor_d : ceil_d;
+
+ // Prioritize trying a simple rounding of the real solution first,
+ // it that fails, fall back on original branch and bound strategy.
+ Node ub = Rewriter::rewrite(
+ nm->mkNode(kind::LEQ, var, mkRationalNode(nearest - 1)));
+ Node lb = Rewriter::rewrite(
+ nm->mkNode(kind::GEQ, var, mkRationalNode(nearest + 1)));
+ lem = nm->mkNode(kind::OR, ub, lb);
+ Node eq = Rewriter::rewrite(
+ nm->mkNode(kind::EQUAL, var, mkRationalNode(nearest)));
+ Node literal = d_containing.getValuation().ensureLiteral(eq);
+ d_containing.getOutputChannel().requirePhase(literal, true);
+ lem = nm->mkNode(kind::OR, literal, lem);
+ }
+ else
+ {
+ Node ub =
+ Rewriter::rewrite(nm->mkNode(kind::LEQ, var, mkRationalNode(floor_d)));
+ Node lb = ub.notNode();
+ lem = nm->mkNode(kind::OR, ub, lb);
+ }
- //Node lem = NodeManager::currentNM()->mkNode(kind::OR, eq, diseq);
- Node lem = NodeManager::currentNM()->mkNode(kind::OR, ub, lb);
Trace("integers") << "integers: branch & bound: " << lem << endl;
if(isSatLiteral(lem[0])) {
Debug("integers") << " " << lem[0] << " == " << getSatValue(lem[0]) << endl;
diff --git a/src/theory/arith/transcendental_solver.cpp b/src/theory/arith/transcendental_solver.cpp
new file mode 100644
index 000000000..665accc0a
--- /dev/null
+++ b/src/theory/arith/transcendental_solver.cpp
@@ -0,0 +1,1475 @@
+/********************* */
+/*! \file transcendental_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of solver for handling transcendental functions.
+ **/
+
+#include "theory/arith/transcendental_solver.h"
+
+#include <cmath>
+#include <set>
+
+#include "expr/node_algorithm.h"
+#include "expr/node_builder.h"
+#include "options/arith_options.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/arith_utilities.h"
+#include "theory/rewriter.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+TranscendentalSolver::TranscendentalSolver(NlModel& m) : d_model(m)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ d_true = nm->mkConst(true);
+ d_false = nm->mkConst(false);
+ d_zero = nm->mkConst(Rational(0));
+ d_one = nm->mkConst(Rational(1));
+ d_neg_one = nm->mkConst(Rational(-1));
+ d_taylor_real_fv = nm->mkBoundVar("x", nm->realType());
+ d_taylor_real_fv_base = nm->mkBoundVar("a", nm->realType());
+ d_taylor_real_fv_base_rem = nm->mkBoundVar("b", nm->realType());
+ d_taylor_degree = options::nlExtTfTaylorDegree();
+}
+
+TranscendentalSolver::~TranscendentalSolver() {}
+
+void TranscendentalSolver::initLastCall(const std::vector<Node>& assertions,
+ const std::vector<Node>& false_asserts,
+ const std::vector<Node>& xts,
+ std::vector<Node>& lems,
+ std::vector<Node>& lemsPp)
+{
+ d_funcCongClass.clear();
+ d_funcMap.clear();
+ d_tf_region.clear();
+
+ NodeManager* nm = NodeManager::currentNM();
+
+ // register the extended function terms
+ std::vector<Node> trNeedsMaster;
+ bool needPi = false;
+ // for computing congruence
+ std::map<Kind, ArgTrie> argTrie;
+ for (unsigned i = 0, xsize = xts.size(); i < xsize; i++)
+ {
+ Node a = xts[i];
+ Kind ak = a.getKind();
+ bool consider = true;
+ // if is an unpurified application of SINE, or it is a transcendental
+ // applied to a trancendental, purify.
+ if (isTranscendentalKind(ak))
+ {
+ // if we've already computed master for a
+ if (d_trMaster.find(a) != d_trMaster.end())
+ {
+ // a master has at least one slave
+ consider = (d_trSlaves.find(a) != d_trSlaves.end());
+ }
+ else
+ {
+ if (ak == SINE)
+ {
+ // always not a master
+ consider = false;
+ }
+ else
+ {
+ for (const Node& ac : a)
+ {
+ if (isTranscendentalKind(ac.getKind()))
+ {
+ consider = false;
+ break;
+ }
+ }
+ }
+ if (!consider)
+ {
+ // wait to assign a master below
+ trNeedsMaster.push_back(a);
+ }
+ else
+ {
+ d_trMaster[a] = a;
+ d_trSlaves[a].insert(a);
+ }
+ }
+ }
+ if (ak == EXPONENTIAL || ak == SINE)
+ {
+ needPi = needPi || (ak == SINE);
+ // if we didn't indicate that it should be purified above
+ if (consider)
+ {
+ std::vector<Node> repList;
+ for (const Node& ac : a)
+ {
+ Node r = d_model.computeConcreteModelValue(ac);
+ repList.push_back(r);
+ }
+ Node aa = argTrie[ak].add(a, repList);
+ if (aa != a)
+ {
+ // apply congruence to pairs of terms that are disequal and congruent
+ Assert(aa.getNumChildren() == a.getNumChildren());
+ Node mvaa = d_model.computeAbstractModelValue(a);
+ Node mvaaa = d_model.computeAbstractModelValue(aa);
+ if (mvaa != mvaaa)
+ {
+ std::vector<Node> exp;
+ for (unsigned j = 0, size = a.getNumChildren(); j < size; j++)
+ {
+ exp.push_back(a[j].eqNode(aa[j]));
+ }
+ Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
+ Node cong_lemma = nm->mkNode(OR, expn.negate(), a.eqNode(aa));
+ lems.push_back(cong_lemma);
+ }
+ }
+ else
+ {
+ // new representative of congruence class
+ d_funcMap[ak].push_back(a);
+ }
+ // add to congruence class
+ d_funcCongClass[aa].push_back(a);
+ }
+ }
+ else if (ak == PI)
+ {
+ Assert(consider);
+ needPi = true;
+ d_funcMap[ak].push_back(a);
+ d_funcCongClass[a].push_back(a);
+ }
+ }
+ // initialize pi if necessary
+ if (needPi && d_pi.isNull())
+ {
+ mkPi();
+ getCurrentPiBounds(lems);
+ }
+
+ if (!lems.empty())
+ {
+ return;
+ }
+
+ // process SINE phase shifting
+ for (const Node& a : trNeedsMaster)
+ {
+ // should not have processed this already
+ Assert(d_trMaster.find(a) == d_trMaster.end());
+ Kind k = a.getKind();
+ Assert(k == SINE || k == EXPONENTIAL);
+ Node y =
+ nm->mkSkolem("y", nm->realType(), "phase shifted trigonometric arg");
+ Node new_a = nm->mkNode(k, y);
+ d_trSlaves[new_a].insert(new_a);
+ d_trSlaves[new_a].insert(a);
+ d_trMaster[a] = new_a;
+ d_trMaster[new_a] = new_a;
+ Node lem;
+ if (k == SINE)
+ {
+ Trace("nl-ext-tf") << "Basis sine : " << new_a << " for " << a
+ << std::endl;
+ Assert(!d_pi.isNull());
+ Node shift = nm->mkSkolem("s", nm->integerType(), "number of shifts");
+ // TODO : do not introduce shift here, instead needs model-based
+ // refinement for constant shifts (cvc4-projects #1284)
+ lem = nm->mkNode(
+ AND,
+ mkValidPhase(y, d_pi),
+ nm->mkNode(
+ ITE,
+ mkValidPhase(a[0], d_pi),
+ a[0].eqNode(y),
+ a[0].eqNode(nm->mkNode(
+ PLUS,
+ y,
+ nm->mkNode(MULT, nm->mkConst(Rational(2)), shift, d_pi)))),
+ new_a.eqNode(a));
+ }
+ else
+ {
+ // do both equalities to ensure that new_a becomes a preregistered term
+ lem = nm->mkNode(AND, a.eqNode(new_a), a[0].eqNode(y));
+ }
+ // note we must do preprocess on this lemma
+ Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : purify : " << lem
+ << std::endl;
+ lemsPp.push_back(lem);
+ }
+
+ if (Trace.isOn("nl-ext-mv"))
+ {
+ Trace("nl-ext-mv") << "Arguments of trancendental functions : "
+ << std::endl;
+ for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
+ {
+ Kind k = tfl.first;
+ if (k == SINE || k == EXPONENTIAL)
+ {
+ for (const Node& tf : tfl.second)
+ {
+ Node v = tf[0];
+ d_model.computeConcreteModelValue(v);
+ d_model.computeAbstractModelValue(v);
+ d_model.printModelValue("nl-ext-mv", v);
+ }
+ }
+ }
+ }
+}
+
+bool TranscendentalSolver::preprocessAssertionsCheckModel(
+ std::vector<Node>& assertions)
+{
+ std::vector<Node> pvars;
+ std::vector<Node> psubs;
+ for (const std::pair<const Node, Node>& tb : d_trMaster)
+ {
+ pvars.push_back(tb.first);
+ psubs.push_back(tb.second);
+ }
+
+ // initialize representation of assertions
+ std::vector<Node> passertions;
+ for (const Node& a : assertions)
+
+ {
+ Node pa = a;
+ if (!pvars.empty())
+ {
+ pa = arithSubstitute(pa, pvars, psubs);
+ pa = Rewriter::rewrite(pa);
+ }
+ if (!pa.isConst() || !pa.getConst<bool>())
+ {
+ Trace("nl-ext-cm-assert") << "- assert : " << pa << std::endl;
+ passertions.push_back(pa);
+ }
+ }
+ // get model bounds for all transcendental functions
+ Trace("nl-ext-cm") << "----- Get bounds for transcendental functions..."
+ << std::endl;
+ for (std::pair<const Kind, std::vector<Node> >& tfs : d_funcMap)
+ {
+ Kind k = tfs.first;
+ for (const Node& tf : tfs.second)
+ {
+ Trace("nl-ext-cm") << "- Term: " << tf << std::endl;
+ bool success = true;
+ // tf is Figure 3 : tf( x )
+ Node bl;
+ Node bu;
+ if (k == PI)
+ {
+ bl = d_pi_bound[0];
+ bu = d_pi_bound[1];
+ }
+ else
+ {
+ std::pair<Node, Node> bounds = getTfModelBounds(tf, d_taylor_degree);
+ bl = bounds.first;
+ bu = bounds.second;
+ if (bl != bu)
+ {
+ d_model.setUsedApproximate();
+ }
+ }
+ if (!bl.isNull() && !bu.isNull())
+ {
+ // for each function in the congruence classe
+ for (const Node& ctf : d_funcCongClass[tf])
+ {
+ // each term in congruence classes should be master terms
+ Assert(d_trSlaves.find(ctf) != d_trSlaves.end());
+ // we set the bounds for each slave of tf
+ for (const Node& stf : d_trSlaves[ctf])
+ {
+ Trace("nl-ext-cm") << "...bound for " << stf << " : [" << bl << ", "
+ << bu << "]" << std::endl;
+ success = d_model.addCheckModelBound(stf, bl, bu);
+ }
+ }
+ }
+ else
+ {
+ Trace("nl-ext-cm") << "...no bound for " << tf << std::endl;
+ }
+ if (!success)
+ {
+ // a bound was conflicting
+ Trace("nl-ext-cm") << "...failed to set bound for " << tf << std::endl;
+ Trace("nl-ext-cm") << "-----" << std::endl;
+ return false;
+ }
+ }
+ }
+ // replace the assertions
+ assertions = passertions;
+ return true;
+}
+
+void TranscendentalSolver::incrementTaylorDegree() { d_taylor_degree++; }
+unsigned TranscendentalSolver::getTaylorDegree() const
+{
+ return d_taylor_degree;
+}
+
+void TranscendentalSolver::processSideEffect(const NlLemmaSideEffect& se)
+{
+ for (const std::tuple<Node, unsigned, Node>& sp : se.d_secantPoint)
+ {
+ Node tf = std::get<0>(sp);
+ unsigned d = std::get<1>(sp);
+ Node c = std::get<2>(sp);
+ d_secant_points[tf][d].push_back(c);
+ }
+}
+
+void TranscendentalSolver::mkPi()
+{
+ NodeManager* nm = NodeManager::currentNM();
+ if (d_pi.isNull())
+ {
+ d_pi = nm->mkNullaryOperator(nm->realType(), PI);
+ d_pi_2 = Rewriter::rewrite(
+ nm->mkNode(MULT, d_pi, nm->mkConst(Rational(1) / Rational(2))));
+ d_pi_neg_2 = Rewriter::rewrite(
+ nm->mkNode(MULT, d_pi, nm->mkConst(Rational(-1) / Rational(2))));
+ d_pi_neg =
+ Rewriter::rewrite(nm->mkNode(MULT, d_pi, nm->mkConst(Rational(-1))));
+ // initialize bounds
+ d_pi_bound[0] = nm->mkConst(Rational(103993) / Rational(33102));
+ d_pi_bound[1] = nm->mkConst(Rational(104348) / Rational(33215));
+ }
+}
+
+void TranscendentalSolver::getCurrentPiBounds(std::vector<Node>& lemmas)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Node pi_lem = nm->mkNode(AND,
+ nm->mkNode(GEQ, d_pi, d_pi_bound[0]),
+ nm->mkNode(LEQ, d_pi, d_pi_bound[1]));
+ lemmas.push_back(pi_lem);
+}
+
+std::vector<Node> TranscendentalSolver::checkTranscendentalInitialRefine()
+{
+ NodeManager* nm = NodeManager::currentNM();
+ std::vector<Node> lemmas;
+ Trace("nl-ext")
+ << "Get initial refinement lemmas for transcendental functions..."
+ << std::endl;
+ for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
+ {
+ Kind k = tfl.first;
+ for (const Node& t : tfl.second)
+ {
+ // initial refinements
+ if (d_tf_initial_refine.find(t) == d_tf_initial_refine.end())
+ {
+ d_tf_initial_refine[t] = true;
+ Node lem;
+ if (k == SINE)
+ {
+ Node symn = nm->mkNode(SINE, nm->mkNode(MULT, d_neg_one, t[0]));
+ symn = Rewriter::rewrite(symn);
+ // Can assume it is its own master since phase is split over 0,
+ // hence -pi <= t[0] <= pi implies -pi <= -t[0] <= pi.
+ d_trMaster[symn] = symn;
+ d_trSlaves[symn].insert(symn);
+ Assert(d_trSlaves.find(t) != d_trSlaves.end());
+ std::vector<Node> children;
+
+ lem = nm->mkNode(AND,
+ // bounds
+ nm->mkNode(AND,
+ nm->mkNode(LEQ, t, d_one),
+ nm->mkNode(GEQ, t, d_neg_one)),
+ // symmetry
+ nm->mkNode(PLUS, t, symn).eqNode(d_zero),
+ // sign
+ nm->mkNode(EQUAL,
+ nm->mkNode(LT, t[0], d_zero),
+ nm->mkNode(LT, t, d_zero)),
+ // zero val
+ nm->mkNode(EQUAL,
+ nm->mkNode(GT, t[0], d_zero),
+ nm->mkNode(GT, t, d_zero)));
+ lem = nm->mkNode(
+ AND,
+ lem,
+ // zero tangent
+ nm->mkNode(AND,
+ nm->mkNode(IMPLIES,
+ nm->mkNode(GT, t[0], d_zero),
+ nm->mkNode(LT, t, t[0])),
+ nm->mkNode(IMPLIES,
+ nm->mkNode(LT, t[0], d_zero),
+ nm->mkNode(GT, t, t[0]))),
+ // pi tangent
+ nm->mkNode(
+ AND,
+ nm->mkNode(IMPLIES,
+ nm->mkNode(LT, t[0], d_pi),
+ nm->mkNode(LT, t, nm->mkNode(MINUS, d_pi, t[0]))),
+ nm->mkNode(
+ IMPLIES,
+ nm->mkNode(GT, t[0], d_pi_neg),
+ nm->mkNode(GT, t, nm->mkNode(MINUS, d_pi_neg, t[0])))));
+ }
+ else if (k == EXPONENTIAL)
+ {
+ // ( exp(x) > 0 ) ^ ( x=0 <=> exp( x ) = 1 ) ^ ( x < 0 <=> exp( x ) <
+ // 1 ) ^ ( x <= 0 V exp( x ) > x + 1 )
+ lem = nm->mkNode(
+ AND,
+ nm->mkNode(GT, t, d_zero),
+ nm->mkNode(EQUAL, t[0].eqNode(d_zero), t.eqNode(d_one)),
+ nm->mkNode(EQUAL,
+ nm->mkNode(LT, t[0], d_zero),
+ nm->mkNode(LT, t, d_one)),
+ nm->mkNode(OR,
+ nm->mkNode(LEQ, t[0], d_zero),
+ nm->mkNode(GT, t, nm->mkNode(PLUS, t[0], d_one))));
+ }
+ if (!lem.isNull())
+ {
+ lemmas.push_back(lem);
+ }
+ }
+ }
+ }
+
+ return lemmas;
+}
+
+std::vector<Node> TranscendentalSolver::checkTranscendentalMonotonic()
+{
+ std::vector<Node> lemmas;
+ Trace("nl-ext") << "Get monotonicity lemmas for transcendental functions..."
+ << std::endl;
+
+ // sort arguments of all transcendentals
+ std::map<Kind, std::vector<Node> > sorted_tf_args;
+ std::map<Kind, std::map<Node, Node> > tf_arg_to_term;
+
+ for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
+ {
+ Kind k = tfl.first;
+ if (k == EXPONENTIAL || k == SINE)
+ {
+ for (const Node& tf : tfl.second)
+ {
+ Node a = tf[0];
+ Node mvaa = d_model.computeAbstractModelValue(a);
+ if (mvaa.isConst())
+ {
+ Trace("nl-ext-tf-mono-debug") << "...tf term : " << a << std::endl;
+ sorted_tf_args[k].push_back(a);
+ tf_arg_to_term[k][a] = tf;
+ }
+ }
+ }
+ }
+
+ SortNlModel smv;
+ smv.d_nlm = &d_model;
+ // sort by concrete values
+ smv.d_isConcrete = true;
+ smv.d_reverse_order = true;
+ for (std::pair<const Kind, std::vector<Node> >& tfl : d_funcMap)
+ {
+ Kind k = tfl.first;
+ if (!sorted_tf_args[k].empty())
+ {
+ std::sort(sorted_tf_args[k].begin(), sorted_tf_args[k].end(), smv);
+ Trace("nl-ext-tf-mono") << "Sorted transcendental function list for " << k
+ << " : " << std::endl;
+ for (unsigned i = 0; i < sorted_tf_args[k].size(); i++)
+ {
+ Node targ = sorted_tf_args[k][i];
+ Node mvatarg = d_model.computeAbstractModelValue(targ);
+ Trace("nl-ext-tf-mono")
+ << " " << targ << " -> " << mvatarg << std::endl;
+ Node t = tf_arg_to_term[k][targ];
+ Node mvat = d_model.computeAbstractModelValue(t);
+ Trace("nl-ext-tf-mono") << " f-val : " << mvat << std::endl;
+ }
+ std::vector<Node> mpoints;
+ std::vector<Node> mpoints_vals;
+ if (k == SINE)
+ {
+ mpoints.push_back(d_pi);
+ mpoints.push_back(d_pi_2);
+ mpoints.push_back(d_zero);
+ mpoints.push_back(d_pi_neg_2);
+ mpoints.push_back(d_pi_neg);
+ }
+ else if (k == EXPONENTIAL)
+ {
+ mpoints.push_back(Node::null());
+ }
+ if (!mpoints.empty())
+ {
+ // get model values for points
+ for (unsigned i = 0; i < mpoints.size(); i++)
+ {
+ Node mpv;
+ if (!mpoints[i].isNull())
+ {
+ mpv = d_model.computeAbstractModelValue(mpoints[i]);
+ Assert(mpv.isConst());
+ }
+ mpoints_vals.push_back(mpv);
+ }
+
+ unsigned mdir_index = 0;
+ int monotonic_dir = -1;
+ Node mono_bounds[2];
+ Node targ, targval, t, tval;
+ for (unsigned i = 0, size = sorted_tf_args[k].size(); i < size; i++)
+ {
+ Node sarg = sorted_tf_args[k][i];
+ Node sargval = d_model.computeAbstractModelValue(sarg);
+ Assert(sargval.isConst());
+ Node s = tf_arg_to_term[k][sarg];
+ Node sval = d_model.computeAbstractModelValue(s);
+ Assert(sval.isConst());
+
+ // increment to the proper monotonicity region
+ bool increment = true;
+ while (increment && mdir_index < mpoints.size())
+ {
+ increment = false;
+ if (mpoints[mdir_index].isNull())
+ {
+ increment = true;
+ }
+ else
+ {
+ Node pval = mpoints_vals[mdir_index];
+ Assert(pval.isConst());
+ if (sargval.getConst<Rational>() < pval.getConst<Rational>())
+ {
+ increment = true;
+ Trace("nl-ext-tf-mono") << "...increment at " << sarg
+ << " since model value is less than "
+ << mpoints[mdir_index] << std::endl;
+ }
+ }
+ if (increment)
+ {
+ tval = Node::null();
+ mono_bounds[1] = mpoints[mdir_index];
+ mdir_index++;
+ monotonic_dir = regionToMonotonicityDir(k, mdir_index);
+ if (mdir_index < mpoints.size())
+ {
+ mono_bounds[0] = mpoints[mdir_index];
+ }
+ else
+ {
+ mono_bounds[0] = Node::null();
+ }
+ }
+ }
+ // store the concavity region
+ d_tf_region[s] = mdir_index;
+ Trace("nl-ext-concavity") << "Transcendental function " << s
+ << " is in region #" << mdir_index;
+ Trace("nl-ext-concavity")
+ << ", arg model value = " << sargval << std::endl;
+
+ if (!tval.isNull())
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ Node mono_lem;
+ if (monotonic_dir == 1
+ && sval.getConst<Rational>() > tval.getConst<Rational>())
+ {
+ mono_lem = nm->mkNode(
+ IMPLIES, nm->mkNode(GEQ, targ, sarg), nm->mkNode(GEQ, t, s));
+ }
+ else if (monotonic_dir == -1
+ && sval.getConst<Rational>() < tval.getConst<Rational>())
+ {
+ mono_lem = nm->mkNode(
+ IMPLIES, nm->mkNode(LEQ, targ, sarg), nm->mkNode(LEQ, t, s));
+ }
+ if (!mono_lem.isNull())
+ {
+ if (!mono_bounds[0].isNull())
+ {
+ Assert(!mono_bounds[1].isNull());
+ mono_lem = nm->mkNode(
+ IMPLIES,
+ nm->mkNode(AND,
+ mkBounded(mono_bounds[0], targ, mono_bounds[1]),
+ mkBounded(mono_bounds[0], sarg, mono_bounds[1])),
+ mono_lem);
+ }
+ Trace("nl-ext-tf-mono")
+ << "Monotonicity lemma : " << mono_lem << std::endl;
+ lemmas.push_back(mono_lem);
+ }
+ }
+ // store the previous values
+ targ = sarg;
+ targval = sargval;
+ t = s;
+ tval = sval;
+ }
+ }
+ }
+ }
+ return lemmas;
+}
+
+std::vector<Node> TranscendentalSolver::checkTranscendentalTangentPlanes(
+ std::map<Node, NlLemmaSideEffect>& lemSE)
+{
+ std::vector<Node> lemmas;
+ Trace("nl-ext") << "Get tangent plane lemmas for transcendental functions..."
+ << std::endl;
+ // this implements Figure 3 of "Satisfiaility Modulo Transcendental Functions
+ // via Incremental Linearization" by Cimatti et al
+ for (std::pair<const Kind, std::vector<Node> >& tfs : d_funcMap)
+ {
+ Kind k = tfs.first;
+ if (k == PI)
+ {
+ // We do not use Taylor approximation for PI currently.
+ // This is because the convergence is extremely slow, and hence an
+ // initial approximation is superior.
+ continue;
+ }
+ Trace("nl-ext-tftp-debug2") << "Taylor variables: " << std::endl;
+ Trace("nl-ext-tftp-debug2")
+ << " taylor_real_fv : " << d_taylor_real_fv << std::endl;
+ Trace("nl-ext-tftp-debug2")
+ << " taylor_real_fv_base : " << d_taylor_real_fv_base << std::endl;
+ Trace("nl-ext-tftp-debug2")
+ << " taylor_real_fv_base_rem : " << d_taylor_real_fv_base_rem
+ << std::endl;
+ Trace("nl-ext-tftp-debug2") << std::endl;
+
+ // we substitute into the Taylor sum P_{n,f(0)}( x )
+
+ for (const Node& tf : tfs.second)
+ {
+ // tf is Figure 3 : tf( x )
+ Trace("nl-ext-tftp") << "Compute tangent planes " << tf << std::endl;
+ // go until max degree is reached, or we don't meet bound criteria
+ for (unsigned d = 1; d <= d_taylor_degree; d++)
+ {
+ Trace("nl-ext-tftp") << "- run at degree " << d << "..." << std::endl;
+ unsigned prev = lemmas.size();
+ if (checkTfTangentPlanesFun(tf, d, lemmas, lemSE))
+ {
+ Trace("nl-ext-tftp")
+ << "...fail, #lemmas = " << (lemmas.size() - prev) << std::endl;
+ break;
+ }
+ else
+ {
+ Trace("nl-ext-tftp") << "...success" << std::endl;
+ }
+ }
+ }
+ }
+
+ return lemmas;
+}
+
+bool TranscendentalSolver::checkTfTangentPlanesFun(
+ Node tf,
+ unsigned d,
+ std::vector<Node>& lemmas,
+ std::map<Node, NlLemmaSideEffect>& lemSE)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = tf.getKind();
+ // this should only be run on master applications
+ Assert(d_trSlaves.find(tf) != d_trSlaves.end());
+
+ // Figure 3 : c
+ Node c = d_model.computeAbstractModelValue(tf[0]);
+ int csign = c.getConst<Rational>().sgn();
+ if (csign == 0)
+ {
+ // no secant/tangent plane is necessary
+ return true;
+ }
+ Assert(csign == 1 || csign == -1);
+
+ // Figure 3: P_l, P_u
+ // mapped to for signs of c
+ std::map<int, Node> poly_approx_bounds[2];
+ std::vector<Node> pbounds;
+ getPolynomialApproximationBoundForArg(k, c, d, pbounds);
+ poly_approx_bounds[0][1] = pbounds[0];
+ poly_approx_bounds[0][-1] = pbounds[1];
+ poly_approx_bounds[1][1] = pbounds[2];
+ poly_approx_bounds[1][-1] = pbounds[3];
+
+ // Figure 3 : v
+ Node v = d_model.computeAbstractModelValue(tf);
+
+ // check value of tf
+ Trace("nl-ext-tftp-debug") << "Process tangent plane refinement for " << tf
+ << ", degree " << d << "..." << std::endl;
+ Trace("nl-ext-tftp-debug") << " value in model : " << v << std::endl;
+ Trace("nl-ext-tftp-debug") << " arg value in model : " << c << std::endl;
+
+ std::vector<Node> taylor_vars;
+ taylor_vars.push_back(d_taylor_real_fv);
+
+ // compute the concavity
+ int region = -1;
+ std::unordered_map<Node, int, NodeHashFunction>::iterator itr =
+ d_tf_region.find(tf);
+ if (itr != d_tf_region.end())
+ {
+ region = itr->second;
+ Trace("nl-ext-tftp-debug") << " region is : " << region << std::endl;
+ }
+ // Figure 3 : conc
+ int concavity = regionToConcavity(k, itr->second);
+ Trace("nl-ext-tftp-debug") << " concavity is : " << concavity << std::endl;
+ if (concavity == 0)
+ {
+ // no secant/tangent plane is necessary
+ return true;
+ }
+ // bounds for which we are this concavity
+ // Figure 3: < l, u >
+ Node bounds[2];
+ if (k == SINE)
+ {
+ bounds[0] = regionToLowerBound(k, region);
+ Assert(!bounds[0].isNull());
+ bounds[1] = regionToUpperBound(k, region);
+ Assert(!bounds[1].isNull());
+ }
+
+ // Figure 3: P
+ Node poly_approx;
+
+ // compute whether this is a tangent refinement or a secant refinement
+ bool is_tangent = false;
+ bool is_secant = false;
+ std::pair<Node, Node> mvb = getTfModelBounds(tf, d);
+ for (unsigned r = 0; r < 2; r++)
+ {
+ Node pab = poly_approx_bounds[r][csign];
+ Node v_pab = r == 0 ? mvb.first : mvb.second;
+ if (!v_pab.isNull())
+ {
+ Trace("nl-ext-tftp-debug2")
+ << "...model value of " << pab << " is " << v_pab << std::endl;
+
+ Assert(v_pab.isConst());
+ Node comp = nm->mkNode(r == 0 ? LT : GT, v, v_pab);
+ Trace("nl-ext-tftp-debug2") << "...compare : " << comp << std::endl;
+ Node compr = Rewriter::rewrite(comp);
+ Trace("nl-ext-tftp-debug2") << "...got : " << compr << std::endl;
+ if (compr == d_true)
+ {
+ // beyond the bounds
+ if (r == 0)
+ {
+ poly_approx = poly_approx_bounds[r][csign];
+ is_tangent = concavity == 1;
+ is_secant = concavity == -1;
+ }
+ else
+ {
+ poly_approx = poly_approx_bounds[r][csign];
+ is_tangent = concavity == -1;
+ is_secant = concavity == 1;
+ }
+ if (Trace.isOn("nl-ext-tftp"))
+ {
+ Trace("nl-ext-tftp") << "*** Outside boundary point (";
+ Trace("nl-ext-tftp") << (r == 0 ? "low" : "high") << ") ";
+ printRationalApprox("nl-ext-tftp", v_pab);
+ Trace("nl-ext-tftp") << ", will refine..." << std::endl;
+ Trace("nl-ext-tftp")
+ << " poly_approx = " << poly_approx << std::endl;
+ Trace("nl-ext-tftp")
+ << " is_tangent = " << is_tangent << std::endl;
+ Trace("nl-ext-tftp") << " is_secant = " << is_secant << std::endl;
+ }
+ break;
+ }
+ else
+ {
+ Trace("nl-ext-tftp")
+ << " ...within " << (r == 0 ? "low" : "high") << " bound : ";
+ printRationalApprox("nl-ext-tftp", v_pab);
+ Trace("nl-ext-tftp") << std::endl;
+ }
+ }
+ }
+
+ // Figure 3: P( c )
+ Node poly_approx_c;
+ if (is_tangent || is_secant)
+ {
+ Assert(!poly_approx.isNull());
+ std::vector<Node> taylor_subs;
+ taylor_subs.push_back(c);
+ Assert(taylor_vars.size() == taylor_subs.size());
+ poly_approx_c = poly_approx.substitute(taylor_vars.begin(),
+ taylor_vars.end(),
+ taylor_subs.begin(),
+ taylor_subs.end());
+ Trace("nl-ext-tftp-debug2")
+ << "...poly approximation at c is " << poly_approx_c << std::endl;
+ }
+ else
+ {
+ // we may want to continue getting better bounds
+ return false;
+ }
+
+ if (is_tangent)
+ {
+ // compute tangent plane
+ // Figure 3: T( x )
+ // We use zero slope tangent planes, since the concavity of the Taylor
+ // approximation cannot be easily established.
+ Node tplane = poly_approx_c;
+
+ Node lem = nm->mkNode(concavity == 1 ? GEQ : LEQ, tf, tplane);
+ std::vector<Node> antec;
+ int mdir = regionToMonotonicityDir(k, region);
+ for (unsigned i = 0; i < 2; i++)
+ {
+ // Tangent plane is valid in the interval [c,u) if the slope of the
+ // function matches its concavity, and is valid in (l, c] otherwise.
+ Node use_bound = (mdir == concavity) == (i == 0) ? c : bounds[i];
+ if (!use_bound.isNull())
+ {
+ Node ant = nm->mkNode(i == 0 ? GEQ : LEQ, tf[0], use_bound);
+ antec.push_back(ant);
+ }
+ }
+ if (!antec.empty())
+ {
+ Node antec_n = antec.size() == 1 ? antec[0] : nm->mkNode(AND, antec);
+ lem = nm->mkNode(IMPLIES, antec_n, lem);
+ }
+ Trace("nl-ext-tftp-debug2")
+ << "*** Tangent plane lemma (pre-rewrite): " << lem << std::endl;
+ lem = Rewriter::rewrite(lem);
+ Trace("nl-ext-tftp-lemma")
+ << "*** Tangent plane lemma : " << lem << std::endl;
+ Assert(d_model.computeAbstractModelValue(lem) == d_false);
+ // Figure 3 : line 9
+ lemmas.push_back(lem);
+ }
+ else if (is_secant)
+ {
+ // bounds are the minimum and maximum previous secant points
+ // should not repeat secant points: secant lemmas should suffice to
+ // rule out previous assignment
+ Assert(std::find(
+ d_secant_points[tf][d].begin(), d_secant_points[tf][d].end(), c)
+ == d_secant_points[tf][d].end());
+ // Insert into the (temporary) vector. We do not update this vector
+ // until we are sure this secant plane lemma has been processed. We do
+ // this by mapping the lemma to a side effect below.
+ std::vector<Node> spoints = d_secant_points[tf][d];
+ spoints.push_back(c);
+
+ // sort
+ SortNlModel smv;
+ smv.d_nlm = &d_model;
+ smv.d_isConcrete = true;
+ std::sort(spoints.begin(), spoints.end(), smv);
+ // get the resulting index of c
+ unsigned index =
+ std::find(spoints.begin(), spoints.end(), c) - spoints.begin();
+ // bounds are the next closest upper/lower bound values
+ if (index > 0)
+ {
+ bounds[0] = spoints[index - 1];
+ }
+ else
+ {
+ // otherwise, we use the lower boundary point for this concavity
+ // region
+ if (k == SINE)
+ {
+ Assert(!bounds[0].isNull());
+ }
+ else if (k == EXPONENTIAL)
+ {
+ // pick c-1
+ bounds[0] = Rewriter::rewrite(nm->mkNode(MINUS, c, d_one));
+ }
+ }
+ if (index < spoints.size() - 1)
+ {
+ bounds[1] = spoints[index + 1];
+ }
+ else
+ {
+ // otherwise, we use the upper boundary point for this concavity
+ // region
+ if (k == SINE)
+ {
+ Assert(!bounds[1].isNull());
+ }
+ else if (k == EXPONENTIAL)
+ {
+ // pick c+1
+ bounds[1] = Rewriter::rewrite(nm->mkNode(PLUS, c, d_one));
+ }
+ }
+ Trace("nl-ext-tftp-debug2") << "...secant bounds are : " << bounds[0]
+ << " ... " << bounds[1] << std::endl;
+
+ // the secant plane may be conjunction of 1-2 guarded inequalities
+ std::vector<Node> lemmaConj;
+ for (unsigned s = 0; s < 2; s++)
+ {
+ // compute secant plane
+ Assert(!poly_approx.isNull());
+ Assert(!bounds[s].isNull());
+ // take the model value of l or u (since may contain PI)
+ Node b = d_model.computeAbstractModelValue(bounds[s]);
+ Trace("nl-ext-tftp-debug2") << "...model value of bound " << bounds[s]
+ << " is " << b << std::endl;
+ Assert(b.isConst());
+ if (c != b)
+ {
+ // Figure 3 : P(l), P(u), for s = 0,1
+ Node poly_approx_b;
+ std::vector<Node> taylor_subs;
+ taylor_subs.push_back(b);
+ Assert(taylor_vars.size() == taylor_subs.size());
+ poly_approx_b = poly_approx.substitute(taylor_vars.begin(),
+ taylor_vars.end(),
+ taylor_subs.begin(),
+ taylor_subs.end());
+ // Figure 3: S_l( x ), S_u( x ) for s = 0,1
+ Node splane;
+ Node rcoeff_n = Rewriter::rewrite(nm->mkNode(MINUS, b, c));
+ Assert(rcoeff_n.isConst());
+ Rational rcoeff = rcoeff_n.getConst<Rational>();
+ Assert(rcoeff.sgn() != 0);
+ poly_approx_b = Rewriter::rewrite(poly_approx_b);
+ poly_approx_c = Rewriter::rewrite(poly_approx_c);
+ splane = nm->mkNode(
+ PLUS,
+ poly_approx_b,
+ nm->mkNode(MULT,
+ nm->mkNode(MINUS, poly_approx_b, poly_approx_c),
+ nm->mkConst(Rational(1) / rcoeff),
+ nm->mkNode(MINUS, tf[0], b)));
+
+ Node lem = nm->mkNode(concavity == 1 ? LEQ : GEQ, tf, splane);
+ // With respect to Figure 3, this is slightly different.
+ // In particular, we chose b to be the model value of bounds[s],
+ // which is a constant although bounds[s] may not be (e.g. if it
+ // contains PI).
+ // To ensure that c...b does not cross an inflection point,
+ // we guard with the symbolic version of bounds[s].
+ // This leads to lemmas e.g. of this form:
+ // ( c <= x <= PI/2 ) => ( sin(x) < ( P( b ) - P( c ) )*( x -
+ // b ) + P( b ) )
+ // where b = (PI/2)^M, the current value of PI/2 in the model.
+ // This is sound since we are guarded by the symbolic
+ // representation of PI/2.
+ Node antec_n =
+ nm->mkNode(AND,
+ nm->mkNode(GEQ, tf[0], s == 0 ? bounds[s] : c),
+ nm->mkNode(LEQ, tf[0], s == 0 ? c : bounds[s]));
+ lem = nm->mkNode(IMPLIES, antec_n, lem);
+ Trace("nl-ext-tftp-debug2")
+ << "*** Secant plane lemma (pre-rewrite) : " << lem << std::endl;
+ lem = Rewriter::rewrite(lem);
+ Trace("nl-ext-tftp-lemma")
+ << "*** Secant plane lemma : " << lem << std::endl;
+ lemmaConj.push_back(lem);
+ Assert(d_model.computeAbstractModelValue(lem) == d_false);
+ }
+ }
+ // Figure 3 : line 22
+ Assert(!lemmaConj.empty());
+ Node lem =
+ lemmaConj.size() == 1 ? lemmaConj[0] : nm->mkNode(AND, lemmaConj);
+ lemmas.push_back(lem);
+ // The side effect says that if lem is added, then we should add the
+ // secant point c for (tf,d).
+ lemSE[lem].d_secantPoint.push_back(std::make_tuple(tf, d, c));
+ }
+ return true;
+}
+
+int TranscendentalSolver::regionToMonotonicityDir(Kind k, int region)
+{
+ if (k == EXPONENTIAL)
+ {
+ if (region == 1)
+ {
+ return 1;
+ }
+ }
+ else if (k == SINE)
+ {
+ if (region == 1 || region == 4)
+ {
+ return -1;
+ }
+ else if (region == 2 || region == 3)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int TranscendentalSolver::regionToConcavity(Kind k, int region)
+{
+ if (k == EXPONENTIAL)
+ {
+ if (region == 1)
+ {
+ return 1;
+ }
+ }
+ else if (k == SINE)
+ {
+ if (region == 1 || region == 2)
+ {
+ return -1;
+ }
+ else if (region == 3 || region == 4)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+Node TranscendentalSolver::regionToLowerBound(Kind k, int region)
+{
+ if (k == SINE)
+ {
+ if (region == 1)
+ {
+ return d_pi_2;
+ }
+ else if (region == 2)
+ {
+ return d_zero;
+ }
+ else if (region == 3)
+ {
+ return d_pi_neg_2;
+ }
+ else if (region == 4)
+ {
+ return d_pi_neg;
+ }
+ }
+ return Node::null();
+}
+
+Node TranscendentalSolver::regionToUpperBound(Kind k, int region)
+{
+ if (k == SINE)
+ {
+ if (region == 1)
+ {
+ return d_pi;
+ }
+ else if (region == 2)
+ {
+ return d_pi_2;
+ }
+ else if (region == 3)
+ {
+ return d_zero;
+ }
+ else if (region == 4)
+ {
+ return d_pi_neg_2;
+ }
+ }
+ return Node::null();
+}
+
+Node TranscendentalSolver::getDerivative(Node n, Node x)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(x.isVar());
+ // only handle the cases of the taylor expansion of d
+ if (n.getKind() == EXPONENTIAL)
+ {
+ if (n[0] == x)
+ {
+ return n;
+ }
+ }
+ else if (n.getKind() == SINE)
+ {
+ if (n[0] == x)
+ {
+ Node na = nm->mkNode(MINUS, d_pi_2, n[0]);
+ Node ret = nm->mkNode(SINE, na);
+ ret = Rewriter::rewrite(ret);
+ return ret;
+ }
+ }
+ else if (n.getKind() == PLUS)
+ {
+ std::vector<Node> dchildren;
+ for (unsigned i = 0; i < n.getNumChildren(); i++)
+ {
+ // PLUS is flattened in rewriter, recursion depth is bounded by 1
+ Node dc = getDerivative(n[i], x);
+ if (dc.isNull())
+ {
+ return dc;
+ }
+ else
+ {
+ dchildren.push_back(dc);
+ }
+ }
+ return nm->mkNode(PLUS, dchildren);
+ }
+ else if (n.getKind() == MULT)
+ {
+ Assert(n[0].isConst());
+ Node dc = getDerivative(n[1], x);
+ if (!dc.isNull())
+ {
+ return nm->mkNode(MULT, n[0], dc);
+ }
+ }
+ else if (n.getKind() == NONLINEAR_MULT)
+ {
+ unsigned xcount = 0;
+ std::vector<Node> children;
+ unsigned xindex = 0;
+ for (unsigned i = 0, size = n.getNumChildren(); i < size; i++)
+ {
+ if (n[i] == x)
+ {
+ xcount++;
+ xindex = i;
+ }
+ children.push_back(n[i]);
+ }
+ if (xcount == 0)
+ {
+ return d_zero;
+ }
+ else
+ {
+ children[xindex] = nm->mkConst(Rational(xcount));
+ }
+ return nm->mkNode(MULT, children);
+ }
+ else if (n.isVar())
+ {
+ return n == x ? d_one : d_zero;
+ }
+ else if (n.isConst())
+ {
+ return d_zero;
+ }
+ Trace("nl-ext-debug") << "No derivative computed for " << n;
+ Trace("nl-ext-debug") << " for d/d{" << x << "}" << std::endl;
+ return Node::null();
+}
+
+std::pair<Node, Node> TranscendentalSolver::getTaylor(Node fa, unsigned n)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(n > 0);
+ Node fac; // what term we cache for fa
+ if (fa[0] == d_zero)
+ {
+ // optimization : simpler to compute (x-fa[0])^n if we are centered around 0
+ fac = fa;
+ }
+ else
+ {
+ // otherwise we use a standard factor a in (x-a)^n
+ fac = nm->mkNode(fa.getKind(), d_taylor_real_fv_base);
+ }
+ Node taylor_rem;
+ Node taylor_sum;
+ // check if we have already computed this Taylor series
+ std::unordered_map<unsigned, Node>::iterator itt = d_taylor_sum[fac].find(n);
+ if (itt == d_taylor_sum[fac].end())
+ {
+ Node i_exp_base;
+ if (fa[0] == d_zero)
+ {
+ i_exp_base = d_taylor_real_fv;
+ }
+ else
+ {
+ i_exp_base = Rewriter::rewrite(
+ nm->mkNode(MINUS, d_taylor_real_fv, d_taylor_real_fv_base));
+ }
+ Node i_derv = fac;
+ Node i_fact = d_one;
+ Node i_exp = d_one;
+ int i_derv_status = 0;
+ unsigned counter = 0;
+ std::vector<Node> sum;
+ do
+ {
+ counter++;
+ if (fa.getKind() == EXPONENTIAL)
+ {
+ // unchanged
+ }
+ else if (fa.getKind() == SINE)
+ {
+ if (i_derv_status % 2 == 1)
+ {
+ Node arg = nm->mkNode(PLUS, d_pi_2, d_taylor_real_fv_base);
+ i_derv = nm->mkNode(SINE, arg);
+ }
+ else
+ {
+ i_derv = fa;
+ }
+ if (i_derv_status >= 2)
+ {
+ i_derv = nm->mkNode(MINUS, d_zero, i_derv);
+ }
+ i_derv = Rewriter::rewrite(i_derv);
+ i_derv_status = i_derv_status == 3 ? 0 : i_derv_status + 1;
+ }
+ if (counter == (n + 1))
+ {
+ TNode x = d_taylor_real_fv_base;
+ i_derv = i_derv.substitute(x, d_taylor_real_fv_base_rem);
+ }
+ Node curr = nm->mkNode(MULT, nm->mkNode(DIVISION, i_derv, i_fact), i_exp);
+ if (counter == (n + 1))
+ {
+ taylor_rem = curr;
+ }
+ else
+ {
+ sum.push_back(curr);
+ i_fact = Rewriter::rewrite(
+ nm->mkNode(MULT, nm->mkConst(Rational(counter)), i_fact));
+ i_exp = Rewriter::rewrite(nm->mkNode(MULT, i_exp_base, i_exp));
+ }
+ } while (counter <= n);
+ taylor_sum = sum.size() == 1 ? sum[0] : nm->mkNode(PLUS, sum);
+
+ if (fac[0] != d_taylor_real_fv_base)
+ {
+ TNode x = d_taylor_real_fv_base;
+ taylor_sum = taylor_sum.substitute(x, fac[0]);
+ }
+
+ // cache
+ d_taylor_sum[fac][n] = taylor_sum;
+ d_taylor_rem[fac][n] = taylor_rem;
+ }
+ else
+ {
+ taylor_sum = itt->second;
+ Assert(d_taylor_rem[fac].find(n) != d_taylor_rem[fac].end());
+ taylor_rem = d_taylor_rem[fac][n];
+ }
+
+ // must substitute for the argument if we were using a different lookup
+ if (fa[0] != fac[0])
+ {
+ TNode x = d_taylor_real_fv_base;
+ taylor_sum = taylor_sum.substitute(x, fa[0]);
+ }
+ return std::pair<Node, Node>(taylor_sum, taylor_rem);
+}
+
+void TranscendentalSolver::getPolynomialApproximationBounds(
+ Kind k, unsigned d, std::vector<Node>& pbounds)
+{
+ if (d_poly_bounds[k][d].empty())
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ Node tft = nm->mkNode(k, d_zero);
+ // n is the Taylor degree we are currently considering
+ unsigned n = 2 * d;
+ // n must be even
+ std::pair<Node, Node> taylor = getTaylor(tft, n);
+ Trace("nl-ext-tftp-debug2")
+ << "Taylor for " << k << " is : " << taylor.first << std::endl;
+ Node taylor_sum = Rewriter::rewrite(taylor.first);
+ Trace("nl-ext-tftp-debug2")
+ << "Taylor for " << k << " is (post-rewrite) : " << taylor_sum
+ << std::endl;
+ Assert(taylor.second.getKind() == MULT);
+ Assert(taylor.second.getNumChildren() == 2);
+ Assert(taylor.second[0].getKind() == DIVISION);
+ Trace("nl-ext-tftp-debug2")
+ << "Taylor remainder for " << k << " is " << taylor.second << std::endl;
+ // ru is x^{n+1}/(n+1)!
+ Node ru = nm->mkNode(DIVISION, taylor.second[1], taylor.second[0][1]);
+ ru = Rewriter::rewrite(ru);
+ Trace("nl-ext-tftp-debug2")
+ << "Taylor remainder factor is (post-rewrite) : " << ru << std::endl;
+ if (k == EXPONENTIAL)
+ {
+ pbounds.push_back(taylor_sum);
+ pbounds.push_back(taylor_sum);
+ pbounds.push_back(Rewriter::rewrite(
+ nm->mkNode(MULT, taylor_sum, nm->mkNode(PLUS, d_one, ru))));
+ pbounds.push_back(Rewriter::rewrite(nm->mkNode(PLUS, taylor_sum, ru)));
+ }
+ else
+ {
+ Assert(k == SINE);
+ Node l = Rewriter::rewrite(nm->mkNode(MINUS, taylor_sum, ru));
+ Node u = Rewriter::rewrite(nm->mkNode(PLUS, taylor_sum, ru));
+ pbounds.push_back(l);
+ pbounds.push_back(l);
+ pbounds.push_back(u);
+ pbounds.push_back(u);
+ }
+ Trace("nl-ext-tf-tplanes")
+ << "Polynomial approximation for " << k << " is: " << std::endl;
+ Trace("nl-ext-tf-tplanes") << " Lower (pos): " << pbounds[0] << std::endl;
+ Trace("nl-ext-tf-tplanes") << " Upper (pos): " << pbounds[2] << std::endl;
+ Trace("nl-ext-tf-tplanes") << " Lower (neg): " << pbounds[1] << std::endl;
+ Trace("nl-ext-tf-tplanes") << " Upper (neg): " << pbounds[3] << std::endl;
+ d_poly_bounds[k][d].insert(
+ d_poly_bounds[k][d].end(), pbounds.begin(), pbounds.end());
+ }
+ else
+ {
+ pbounds.insert(
+ pbounds.end(), d_poly_bounds[k][d].begin(), d_poly_bounds[k][d].end());
+ }
+}
+
+void TranscendentalSolver::getPolynomialApproximationBoundForArg(
+ Kind k, Node c, unsigned d, std::vector<Node>& pbounds)
+{
+ getPolynomialApproximationBounds(k, d, pbounds);
+ Assert(c.isConst());
+ if (k == EXPONENTIAL && c.getConst<Rational>().sgn() == 1)
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ Node tft = nm->mkNode(k, d_zero);
+ bool success = false;
+ unsigned ds = d;
+ TNode ttrf = d_taylor_real_fv;
+ TNode tc = c;
+ do
+ {
+ success = true;
+ unsigned n = 2 * ds;
+ std::pair<Node, Node> taylor = getTaylor(tft, n);
+ // check that 1-c^{n+1}/(n+1)! > 0
+ Node ru = nm->mkNode(DIVISION, taylor.second[1], taylor.second[0][1]);
+ Node rus = ru.substitute(ttrf, tc);
+ rus = Rewriter::rewrite(rus);
+ Assert(rus.isConst());
+ if (rus.getConst<Rational>() > d_one.getConst<Rational>())
+ {
+ success = false;
+ ds = ds + 1;
+ }
+ } while (!success);
+ if (ds > d)
+ {
+ Trace("nl-ext-exp-taylor")
+ << "*** Increase Taylor bound to " << ds << " > " << d << " for ("
+ << k << " " << c << ")" << std::endl;
+ // must use sound upper bound
+ std::vector<Node> pboundss;
+ getPolynomialApproximationBounds(k, ds, pboundss);
+ pbounds[2] = pboundss[2];
+ }
+ }
+}
+
+std::pair<Node, Node> TranscendentalSolver::getTfModelBounds(Node tf,
+ unsigned d)
+{
+ // compute the model value of the argument
+ Node c = d_model.computeAbstractModelValue(tf[0]);
+ Assert(c.isConst());
+ int csign = c.getConst<Rational>().sgn();
+ Kind k = tf.getKind();
+ if (csign == 0)
+ {
+ // at zero, its trivial
+ if (k == SINE)
+ {
+ return std::pair<Node, Node>(d_zero, d_zero);
+ }
+ Assert(k == EXPONENTIAL);
+ return std::pair<Node, Node>(d_one, d_one);
+ }
+ bool isNeg = csign == -1;
+
+ std::vector<Node> pbounds;
+ getPolynomialApproximationBoundForArg(k, c, d, pbounds);
+
+ std::vector<Node> bounds;
+ TNode tfv = d_taylor_real_fv;
+ TNode tfs = tf[0];
+ for (unsigned d2 = 0; d2 < 2; d2++)
+ {
+ int index = d2 == 0 ? (isNeg ? 1 : 0) : (isNeg ? 3 : 2);
+ Node pab = pbounds[index];
+ if (!pab.isNull())
+ {
+ // { x -> tf[0] }
+ pab = pab.substitute(tfv, tfs);
+ pab = Rewriter::rewrite(pab);
+ Node v_pab = d_model.computeAbstractModelValue(pab);
+ bounds.push_back(v_pab);
+ }
+ else
+ {
+ bounds.push_back(Node::null());
+ }
+ }
+ return std::pair<Node, Node>(bounds[0], bounds[1]);
+}
+
+Node TranscendentalSolver::mkValidPhase(Node a, Node pi)
+{
+ return mkBounded(
+ NodeManager::currentNM()->mkNode(MULT, mkRationalNode(-1), pi), a, pi);
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/transcendental_solver.h b/src/theory/arith/transcendental_solver.h
new file mode 100644
index 000000000..8e539bbf0
--- /dev/null
+++ b/src/theory/arith/transcendental_solver.h
@@ -0,0 +1,419 @@
+/********************* */
+/*! \file transcendental_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Solving for handling transcendental functions.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__TRANSCENDENTAL_SOLVER_H
+#define CVC4__THEORY__ARITH__TRANSCENDENTAL_SOLVER_H
+
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/arith/nl_lemma_utils.h"
+#include "theory/arith/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+/** Transcendental solver class
+ *
+ * This class implements model-based refinement schemes
+ * for transcendental functions, described in:
+ *
+ * - "Satisfiability Modulo Transcendental
+ * Functions via Incremental Linearization" by Cimatti
+ * et al., CADE 2017.
+ *
+ * It's main functionality are methods that implement lemma schemas below,
+ * which return a set of lemmas that should be sent on the output channel.
+ */
+class TranscendentalSolver
+{
+ public:
+ TranscendentalSolver(NlModel& m);
+ ~TranscendentalSolver();
+
+ /** init last call
+ */
+ void initLastCall(const std::vector<Node>& assertions,
+ const std::vector<Node>& false_asserts,
+ const std::vector<Node>& xts,
+ std::vector<Node>& lems,
+ std::vector<Node>& lemsPp);
+ /** increment taylor degree */
+ void incrementTaylorDegree();
+ /** get taylor degree */
+ unsigned getTaylorDegree() const;
+ /** preprocess assertions check model
+ *
+ * This modifies the given assertions in preparation for running a call
+ * to check model.
+ *
+ * This method returns false if a bound for a transcendental function
+ * was conflicting.
+ */
+ bool preprocessAssertionsCheckModel(std::vector<Node>& assertions);
+ /** Process side effect se */
+ void processSideEffect(const NlLemmaSideEffect& se);
+ //-------------------------------------------- lemma schemas
+ /** check transcendental initial refine
+ *
+ * Returns a set of valid theory lemmas, based on
+ * simple facts about transcendental functions.
+ * This mostly follows the initial axioms described in
+ * Section 4 of "Satisfiability
+ * Modulo Transcendental Functions via Incremental
+ * Linearization" by Cimatti et al., CADE 2017.
+ *
+ * Examples:
+ *
+ * sin( x ) = -sin( -x )
+ * ( PI > x > 0 ) => 0 < sin( x ) < 1
+ * exp( x )>0
+ * x<0 => exp( x )<1
+ */
+ std::vector<Node> checkTranscendentalInitialRefine();
+
+ /** check transcendental monotonic
+ *
+ * Returns a set of valid theory lemmas, based on a
+ * lemma scheme that ensures that applications
+ * of transcendental functions respect monotonicity.
+ *
+ * Examples:
+ *
+ * x > y => exp( x ) > exp( y )
+ * PI/2 > x > y > 0 => sin( x ) > sin( y )
+ * PI > x > y > PI/2 => sin( x ) < sin( y )
+ */
+ std::vector<Node> checkTranscendentalMonotonic();
+
+ /** check transcendental tangent planes
+ *
+ * Returns a set of valid theory lemmas, based on
+ * computing an "incremental linearization" of
+ * transcendental functions based on the model values
+ * of transcendental functions and their arguments.
+ * It is based on Figure 3 of "Satisfiability
+ * Modulo Transcendental Functions via Incremental
+ * Linearization" by Cimatti et al., CADE 2017.
+ * This schema is not terminating in general.
+ * It is not enabled by default, and can
+ * be enabled by --nl-ext-tf-tplanes.
+ *
+ * Example:
+ *
+ * Assume we have a term sin(y) where M( y ) = 1 where M is the current model.
+ * Note that:
+ * sin(1) ~= .841471
+ *
+ * The Taylor series and remainder of sin(y) of degree 7 is
+ * P_{7,sin(0)}( x ) = x + (-1/6)*x^3 + (1/20)*x^5
+ * R_{7,sin(0),b}( x ) = (-1/5040)*x^7
+ *
+ * This gives us lower and upper bounds :
+ * P_u( x ) = P_{7,sin(0)}( x ) + R_{7,sin(0),b}( x )
+ * ...where note P_u( 1 ) = 4243/5040 ~= .841865
+ * P_l( x ) = P_{7,sin(0)}( x ) - R_{7,sin(0),b}( x )
+ * ...where note P_l( 1 ) = 4241/5040 ~= .841468
+ *
+ * Assume that M( sin(y) ) > P_u( 1 ).
+ * Since the concavity of sine in the region 0 < x < PI/2 is -1,
+ * we add a tangent plane refinement.
+ * The tangent plane at the point 1 in P_u is
+ * given by the formula:
+ * T( x ) = P_u( 1 ) + ((d/dx)(P_u(x)))( 1 )*( x - 1 )
+ * We add the lemma:
+ * ( 0 < y < PI/2 ) => sin( y ) <= T( y )
+ * which is:
+ * ( 0 < y < PI/2 ) => sin( y ) <= (391/720)*(y - 2737/1506)
+ *
+ * Assume that M( sin(y) ) < P_u( 1 ).
+ * Since the concavity of sine in the region 0 < x < PI/2 is -1,
+ * we add a secant plane refinement for some constants ( l, u )
+ * such that 0 <= l < M( y ) < u <= PI/2. Assume we choose
+ * l = 0 and u = M( PI/2 ) = 150517/47912.
+ * The secant planes at point 1 for P_l
+ * are given by the formulas:
+ * S_l( x ) = (x-l)*(P_l( l )-P_l(c))/(l-1) + P_l( l )
+ * S_u( x ) = (x-u)*(P_l( u )-P_l(c))/(u-1) + P_l( u )
+ * We add the lemmas:
+ * ( 0 < y < 1 ) => sin( y ) >= S_l( y )
+ * ( 1 < y < PI/2 ) => sin( y ) >= S_u( y )
+ * which are:
+ * ( 0 < y < 1 ) => (sin y) >= 4251/5040*y
+ * ( 1 < y < PI/2 ) => (sin y) >= c1*(y+c2)
+ * where c1, c2 are rationals (for brevity, omitted here)
+ * such that c1 ~= .277 and c2 ~= 2.032.
+ *
+ * The argument lemSE is the "side effect" of the lemmas in the return
+ * value of this function (for details, see checkLastCall).
+ */
+ std::vector<Node> checkTranscendentalTangentPlanes(
+ std::map<Node, NlLemmaSideEffect>& lemSE);
+ /** check transcendental function refinement for tf
+ *
+ * This method is called by the above method for each "master"
+ * transcendental function application that occurs in an assertion in the
+ * current context. For example, an application like sin(t) is not a master
+ * if we have introduced the constraints:
+ * t=y+2*pi*n ^ -pi <= y <= pi ^ sin(t) = sin(y).
+ * See d_trMaster/d_trSlaves for more detail.
+ *
+ * This runs Figure 3 of Cimatti et al., CADE 2017 for transcendental
+ * function application tf for Taylor degree d. It may add a secant or
+ * tangent plane lemma to lems and its side effect (if one exists)
+ * to lemSE.
+ *
+ * It returns false if the bounds are not precise enough to add a
+ * secant or tangent plane lemma.
+ */
+ bool checkTfTangentPlanesFun(Node tf,
+ unsigned d,
+ std::vector<Node>& lems,
+ std::map<Node, NlLemmaSideEffect>& lemSE);
+ //-------------------------------------------- end lemma schemas
+ private:
+ /** polynomial approximation bounds
+ *
+ * This adds P_l+[x], P_l-[x], P_u+[x], P_u-[x] to pbounds, where x is
+ * d_taylor_real_fv. These are polynomial approximations of the Taylor series
+ * of <k>( 0 ) for degree 2*d where k is SINE or EXPONENTIAL.
+ * These correspond to P_l and P_u from Figure 3 of Cimatti et al., CADE 2017,
+ * for positive/negative (+/-) values of the argument of <k>( 0 ).
+ *
+ * Notice that for certain bounds (e.g. upper bounds for exponential), the
+ * Taylor approximation for a fixed degree is only sound up to a given
+ * upper bound on the argument. To obtain sound lower/upper bounds for a
+ * given <k>( c ), use the function below.
+ */
+ void getPolynomialApproximationBounds(Kind k,
+ unsigned d,
+ std::vector<Node>& pbounds);
+ /** polynomial approximation bounds
+ *
+ * This computes polynomial approximations P_l+[x], P_l-[x], P_u+[x], P_u-[x]
+ * that are sound (lower, upper) bounds for <k>( c ). Notice that these
+ * polynomials may depend on c. In particular, for P_u+[x] for <k>( c ) where
+ * c>0, we return the P_u+[x] from the function above for the minimum degree
+ * d' >= d such that (1-c^{2*d'+1}/(2*d'+1)!) is positive.
+ */
+ void getPolynomialApproximationBoundForArg(Kind k,
+ Node c,
+ unsigned d,
+ std::vector<Node>& pbounds);
+ /** get transcendental function model bounds
+ *
+ * This returns the current lower and upper bounds of transcendental
+ * function application tf based on Taylor of degree 2*d, which is dependent
+ * on the model value of its argument.
+ */
+ std::pair<Node, Node> getTfModelBounds(Node tf, unsigned d);
+ /** get monotonicity direction
+ *
+ * Returns whether the slope is positive (+1) or negative(-1)
+ * in region of transcendental function with kind k.
+ * Returns 0 if region is invalid.
+ */
+ int regionToMonotonicityDir(Kind k, int region);
+ /** get concavity
+ *
+ * Returns whether we are concave (+1) or convex (-1)
+ * in region of transcendental function with kind k,
+ * where region is defined above.
+ * Returns 0 if region is invalid.
+ */
+ int regionToConcavity(Kind k, int region);
+ /** region to lower bound
+ *
+ * Returns the term corresponding to the lower
+ * bound of the region of transcendental function
+ * with kind k. Returns Node::null if the region
+ * is invalid, or there is no lower bound for the
+ * region.
+ */
+ Node regionToLowerBound(Kind k, int region);
+ /** region to upper bound
+ *
+ * Returns the term corresponding to the upper
+ * bound of the region of transcendental function
+ * with kind k. Returns Node::null if the region
+ * is invalid, or there is no upper bound for the
+ * region.
+ */
+ Node regionToUpperBound(Kind k, int region);
+ /** get derivative
+ *
+ * Returns d/dx n. Supports cases of n
+ * for transcendental functions applied to x,
+ * multiplication, addition, constants and variables.
+ * Returns Node::null() if derivative is an
+ * unhandled case.
+ */
+ Node getDerivative(Node n, Node x);
+
+ void mkPi();
+ void getCurrentPiBounds(std::vector<Node>& lemmas);
+ /** Make the node -pi <= a <= pi */
+ static Node mkValidPhase(Node a, Node pi);
+
+ /** Reference to the non-linear model object */
+ NlModel& d_model;
+ /** commonly used terms */
+ Node d_zero;
+ Node d_one;
+ Node d_neg_one;
+ Node d_true;
+ Node d_false;
+ /**
+ * Some transcendental functions f(t) are "purified", e.g. we add
+ * t = y ^ f(t) = f(y) where y is a fresh variable. Those that are not
+ * purified we call "master terms".
+ *
+ * The maps below maintain a master/slave relationship over
+ * transcendental functions (SINE, EXPONENTIAL, PI), where above
+ * f(y) is the master of itself and of f(t).
+ *
+ * This is used for ensuring that the argument y of SINE we process is on the
+ * interval [-pi .. pi], and that exponentials are not applied to arguments
+ * that contain transcendental functions.
+ */
+ std::map<Node, Node> d_trMaster;
+ std::map<Node, std::unordered_set<Node, NodeHashFunction>> d_trSlaves;
+ /** The transcendental functions we have done initial refinements on */
+ std::map<Node, bool> d_tf_initial_refine;
+
+ /** concavity region for transcendental functions
+ *
+ * This stores an integer that identifies an interval in
+ * which the current model value for an argument of an
+ * application of a transcendental function resides.
+ *
+ * For exp( x ):
+ * region #1 is -infty < x < infty
+ * For sin( x ):
+ * region #0 is pi < x < infty (this is an invalid region)
+ * region #1 is pi/2 < x <= pi
+ * region #2 is 0 < x <= pi/2
+ * region #3 is -pi/2 < x <= 0
+ * region #4 is -pi < x <= -pi/2
+ * region #5 is -infty < x <= -pi (this is an invalid region)
+ * All regions not listed above, as well as regions 0 and 5
+ * for SINE are "invalid". We only process applications
+ * of transcendental functions whose arguments have model
+ * values that reside in valid regions.
+ */
+ std::unordered_map<Node, int, NodeHashFunction> d_tf_region;
+ /** cache of the above function */
+ std::map<Kind, std::map<unsigned, std::vector<Node>>> d_poly_bounds;
+
+ /**
+ * Maps representives of a congruence class to the members of that class.
+ *
+ * In detail, a congruence class is a set of terms of the form
+ * { f(t1), ..., f(tn) }
+ * such that t1 = ... = tn in the current context. We choose an arbitrary
+ * term among these to be the repesentative of this congruence class.
+ *
+ * Moreover, notice we compute congruence classes only over terms that
+ * are transcendental function applications that are "master terms",
+ * see d_trMaster/d_trSlave.
+ */
+ std::map<Node, std::vector<Node>> d_funcCongClass;
+ /**
+ * A list of all functions for each kind in { EXPONENTIAL, SINE, POW, PI }
+ * that are representives of their congruence class.
+ */
+ std::map<Kind, std::vector<Node>> d_funcMap;
+
+ // tangent plane bounds
+ std::map<Node, std::map<Node, Node>> d_tangent_val_bound[4];
+
+ /** secant points (sorted list) for transcendental functions
+ *
+ * This is used for tangent plane refinements for
+ * transcendental functions. This is the set
+ * "get-previous-secant-points" in "Satisfiability
+ * Modulo Transcendental Functions via Incremental
+ * Linearization" by Cimatti et al., CADE 2017, for
+ * each transcendental function application. We store this set for each
+ * Taylor degree.
+ */
+ std::unordered_map<Node,
+ std::map<unsigned, std::vector<Node>>,
+ NodeHashFunction>
+ d_secant_points;
+
+ /** get Taylor series of degree n for function fa centered around point fa[0].
+ *
+ * Return value is ( P_{n,f(a)}( x ), R_{n+1,f(a)}( x ) ) where
+ * the first part of the pair is the Taylor series expansion :
+ * P_{n,f(a)}( x ) = sum_{i=0}^n (f^i( a )/i!)*(x-a)^i
+ * and the second part of the pair is the Taylor series remainder :
+ * R_{n+1,f(a),b}( x ) = (f^{n+1}( b )/(n+1)!)*(x-a)^{n+1}
+ *
+ * The above values are cached for each (f,n) for a fixed variable "a".
+ * To compute the Taylor series for fa, we compute the Taylor series
+ * for ( fa.getKind(), n ) then substitute { a -> fa[0] } if fa[0]!=0.
+ * We compute P_{n,f(0)}( x )/R_{n+1,f(0),b}( x ) for ( fa.getKind(), n )
+ * if fa[0]=0.
+ * In the latter case, note we compute the exponential x^{n+1}
+ * instead of (x-a)^{n+1}, which can be done faster.
+ */
+ std::pair<Node, Node> getTaylor(Node fa, unsigned n);
+
+ /** internal variables used for constructing (cached) versions of the Taylor
+ * series above.
+ */
+ Node d_taylor_real_fv; // x above
+ Node d_taylor_real_fv_base; // a above
+ Node d_taylor_real_fv_base_rem; // b above
+
+ /** cache of sum and remainder terms for getTaylor */
+ std::unordered_map<Node, std::unordered_map<unsigned, Node>, NodeHashFunction>
+ d_taylor_sum;
+ std::unordered_map<Node, std::unordered_map<unsigned, Node>, NodeHashFunction>
+ d_taylor_rem;
+ /** taylor degree
+ *
+ * Indicates that the degree of the polynomials in the Taylor approximation of
+ * all transcendental functions is 2*d_taylor_degree. This value is set
+ * initially to options::nlExtTfTaylorDegree() and may be incremented
+ * if the option options::nlExtTfIncPrecision() is enabled.
+ */
+ unsigned d_taylor_degree;
+ /** PI
+ *
+ * Note that PI is a (symbolic, non-constant) nullary operator. This is
+ * because its value cannot be computed exactly. We constraint PI to concrete
+ * lower and upper bounds stored in d_pi_bound below.
+ */
+ Node d_pi;
+ /** PI/2 */
+ Node d_pi_2;
+ /** -PI/2 */
+ Node d_pi_neg_2;
+ /** -PI */
+ Node d_pi_neg;
+ /** the concrete lower and upper bounds for PI */
+ Node d_pi_bound[2];
+}; /* class TranscendentalSolver */
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__TRANSCENDENTAL_SOLVER_H */
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index dcf82e6b4..787ae84e2 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -29,6 +29,7 @@
#include "smt/command.h"
#include "smt/logic_exception.h"
#include "smt/smt_statistics_registry.h"
+#include "theory/arrays/theory_arrays_rewriter.h"
#include "theory/rewriter.h"
#include "theory/theory_model.h"
#include "theory/valuation.h"
@@ -178,6 +179,11 @@ TheoryArrays::~TheoryArrays() {
smtStatisticsRegistry()->unregisterStat(&d_numSetModelValConflicts);
}
+std::unique_ptr<TheoryRewriter> TheoryArrays::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheoryArraysRewriter());
+}
+
void TheoryArrays::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h
index 3d6d0692e..d1f912d95 100644
--- a/src/theory/arrays/theory_arrays.h
+++ b/src/theory/arrays/theory_arrays.h
@@ -144,6 +144,8 @@ class TheoryArrays : public Theory {
std::string name = "");
~TheoryArrays();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
std::string identify() const override { return std::string("TheoryArrays"); }
diff --git a/src/theory/booleans/theory_bool.cpp b/src/theory/booleans/theory_bool.cpp
index 8fbe83951..e670121d1 100644
--- a/src/theory/booleans/theory_bool.cpp
+++ b/src/theory/booleans/theory_bool.cpp
@@ -14,15 +14,17 @@
** The theory of booleans.
**/
-#include "theory/theory.h"
#include "theory/booleans/theory_bool.h"
-#include "theory/booleans/circuit_propagator.h"
-#include "theory/valuation.h"
-#include "smt_util/boolean_simplification.h"
-#include "theory/substitutions.h"
-#include <vector>
#include <stack>
+#include <vector>
+
+#include "smt_util/boolean_simplification.h"
+#include "theory/booleans/circuit_propagator.h"
+#include "theory/booleans/theory_bool_rewriter.h"
+#include "theory/substitutions.h"
+#include "theory/theory.h"
+#include "theory/valuation.h"
#include "util/hash.h"
using namespace std;
@@ -31,6 +33,11 @@ namespace CVC4 {
namespace theory {
namespace booleans {
+std::unique_ptr<TheoryRewriter> TheoryBool::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheoryBoolRewriter());
+}
+
Theory::PPAssertStatus TheoryBool::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
if (in.getKind() == kind::CONST_BOOLEAN && !in.getConst<bool>()) {
diff --git a/src/theory/booleans/theory_bool.h b/src/theory/booleans/theory_bool.h
index abe024282..75e375ee6 100644
--- a/src/theory/booleans/theory_bool.h
+++ b/src/theory/booleans/theory_bool.h
@@ -33,6 +33,8 @@ public:
: Theory(THEORY_BOOL, c, u, out, valuation, logicInfo)
{}
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
//void check(Effort);
diff --git a/src/theory/builtin/theory_builtin.cpp b/src/theory/builtin/theory_builtin.cpp
index b819b883d..8df5a8535 100644
--- a/src/theory/builtin/theory_builtin.cpp
+++ b/src/theory/builtin/theory_builtin.cpp
@@ -15,9 +15,11 @@
**/
#include "theory/builtin/theory_builtin.h"
-#include "theory/valuation.h"
+
#include "expr/kind.h"
+#include "theory/builtin/theory_builtin_rewriter.h"
#include "theory/theory_model.h"
+#include "theory/valuation.h"
using namespace std;
@@ -25,6 +27,33 @@ namespace CVC4 {
namespace theory {
namespace builtin {
-}/* CVC4::theory::builtin namespace */
-}/* CVC4::theory */
-}/* CVC4 namespace */
+TheoryBuiltin::TheoryBuiltin(context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo)
+ : Theory(THEORY_BUILTIN, c, u, out, valuation, logicInfo)
+{
+}
+
+std::unique_ptr<TheoryRewriter> TheoryBuiltin::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheoryBuiltinRewriter());
+}
+
+std::string TheoryBuiltin::identify() const
+{
+ return std::string("TheoryBuiltin");
+}
+
+void TheoryBuiltin::finishInit()
+{
+ // choice nodes are not evaluated in getModelValue
+ TheoryModel* theoryModel = d_valuation.getModel();
+ Assert(theoryModel != nullptr);
+ theoryModel->setUnevaluatedKind(kind::CHOICE);
+}
+
+} // namespace builtin
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/builtin/theory_builtin.h b/src/theory/builtin/theory_builtin.h
index 8a7d1bf7b..d240f4f63 100644
--- a/src/theory/builtin/theory_builtin.h
+++ b/src/theory/builtin/theory_builtin.h
@@ -25,17 +25,25 @@ namespace CVC4 {
namespace theory {
namespace builtin {
-class TheoryBuiltin : public Theory {
-public:
- TheoryBuiltin(context::Context* c, context::UserContext* u,
- OutputChannel& out, Valuation valuation,
- const LogicInfo& logicInfo)
- : Theory(THEORY_BUILTIN, c, u, out, valuation, logicInfo) {}
- std::string identify() const override { return std::string("TheoryBuiltin"); }
-};/* class TheoryBuiltin */
-
-}/* CVC4::theory::builtin namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
+class TheoryBuiltin : public Theory
+{
+ public:
+ TheoryBuiltin(context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo);
+
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
+ std::string identify() const override;
+
+ /** finish initialization */
+ void finishInit() override;
+}; /* class TheoryBuiltin */
+
+} // namespace builtin
+} // namespace theory
+} // namespace CVC4
#endif /* CVC4__THEORY__BUILTIN__THEORY_BUILTIN_H */
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 94fc1e34c..27718b63f 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -112,6 +112,11 @@ TheoryBV::TheoryBV(context::Context* c,
TheoryBV::~TheoryBV() {}
+std::unique_ptr<TheoryRewriter> TheoryBV::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheoryBVRewriter());
+}
+
void TheoryBV::setMasterEqualityEngine(eq::EqualityEngine* eq) {
if (options::bitblastMode() == options::BitblastMode::EAGER)
{
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 196535a19..ff1c9245a 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -72,6 +72,8 @@ public:
~TheoryBV();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
void finishInit() override;
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index d202648f4..15220b9dc 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -25,6 +25,7 @@
#include "options/quantifiers_options.h"
#include "options/smt_options.h"
#include "options/theory_options.h"
+#include "theory/datatypes/datatypes_rewriter.h"
#include "theory/datatypes/theory_datatypes_type_rules.h"
#include "theory/datatypes/theory_datatypes_utils.h"
#include "theory/quantifiers_engine.h"
@@ -85,6 +86,11 @@ TheoryDatatypes::~TheoryDatatypes() {
}
}
+std::unique_ptr<TheoryRewriter> TheoryDatatypes::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new DatatypesRewriter());
+}
+
void TheoryDatatypes::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
@@ -1306,15 +1312,7 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
Trace("dt-collapse-sel") << "collapse selector : " << s << " " << c << std::endl;
Node r;
bool wrong = false;
- Node use_s;
- Node eq_exp;
- if( options::dtRefIntro() ){
- eq_exp = d_true;
- use_s = getTermSkolemFor( c );
- }else{
- eq_exp = c.eqNode( s[0] );
- use_s = s;
- }
+ Node eq_exp = c.eqNode(s[0]);
if( s.getKind()==kind::APPLY_SELECTOR_TOTAL ){
Node selector = s.getOperator();
size_t constructorIndex = utils::indexOf(c.getOperator());
@@ -1322,14 +1320,7 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
const DTypeConstructor& dtc = dt[constructorIndex];
int selectorIndex = dtc.getSelectorIndexInternal(selector);
wrong = selectorIndex<0;
-
- //if( wrong ){
- // return;
- //}
r = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), c );
- if( options::dtRefIntro() ){
- use_s = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), use_s );
- }
}
if( !r.isNull() ){
Node rr = Rewriter::rewrite( r );
@@ -1341,14 +1332,10 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
std::map< Node, Node > visited;
rrs = removeUninterpretedConstants( rr, visited );
}
- if( use_s!=rrs ){
- Node eq = use_s.eqNode( rrs );
- Node peq;
- if( options::dtRefIntro() ){
- peq = d_true;
- }else{
- peq = c.eqNode(s[0]);
- }
+ if (s != rrs)
+ {
+ Node eq = s.eqNode(rrs);
+ Node peq = c.eqNode(s[0]);
Trace("datatypes-infer") << "DtInfer : collapse sel";
//Trace("datatypes-infer") << ( wrong ? " wrong" : "");
Trace("datatypes-infer") << " : " << eq << " by " << peq << std::endl;
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index a878647bc..7ccd04f39 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -271,6 +271,8 @@ private:
const LogicInfo& logicInfo);
~TheoryDatatypes();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
/** propagate */
diff --git a/src/theory/evaluator.cpp b/src/theory/evaluator.cpp
index b827912d5..646f903f5 100644
--- a/src/theory/evaluator.cpp
+++ b/src/theory/evaluator.cpp
@@ -626,8 +626,7 @@ EvalResult Evaluator::evalInternal(
const String& s = results[currNode[0]].d_str;
if (s.size() == 1)
{
- results[currNode] = EvalResult(
- Rational(String::convertUnsignedIntToCode(s.getVec()[0])));
+ results[currNode] = EvalResult(Rational(s.getVec()[0]));
}
else
{
diff --git a/src/theory/evaluator.h b/src/theory/evaluator.h
index 58e179fbe..b9b15c6c6 100644
--- a/src/theory/evaluator.h
+++ b/src/theory/evaluator.h
@@ -27,7 +27,7 @@
#include "expr/node.h"
#include "util/bitvector.h"
#include "util/rational.h"
-#include "util/regexp.h"
+#include "util/string.h"
namespace CVC4 {
namespace theory {
diff --git a/src/theory/fp/theory_fp.cpp b/src/theory/fp/theory_fp.cpp
index 2632a6f38..5ab285766 100644
--- a/src/theory/fp/theory_fp.cpp
+++ b/src/theory/fp/theory_fp.cpp
@@ -15,18 +15,18 @@
** \todo document this file
**/
-
-#include "options/fp_options.h"
-#include "theory/rewriter.h"
-#include "theory/theory_model.h"
#include "theory/fp/theory_fp.h"
-
#include <set>
#include <stack>
#include <unordered_set>
#include <vector>
+#include "options/fp_options.h"
+#include "theory/fp/theory_fp_rewriter.h"
+#include "theory/rewriter.h"
+#include "theory/theory_model.h"
+
using namespace std;
namespace CVC4 {
@@ -177,6 +177,11 @@ TheoryFp::TheoryFp(context::Context *c,
} /* TheoryFp::TheoryFp() */
+std::unique_ptr<TheoryRewriter> TheoryFp::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheoryFpRewriter());
+}
+
Node TheoryFp::minUF(Node node) {
Assert(node.getKind() == kind::FLOATINGPOINT_MIN);
TypeNode t(node.getType());
diff --git a/src/theory/fp/theory_fp.h b/src/theory/fp/theory_fp.h
index ad093f924..802a70435 100644
--- a/src/theory/fp/theory_fp.h
+++ b/src/theory/fp/theory_fp.h
@@ -38,6 +38,8 @@ class TheoryFp : public Theory {
TheoryFp(context::Context* c, context::UserContext* u, OutputChannel& out,
Valuation valuation, const LogicInfo& logicInfo);
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
Node expandDefinition(LogicRequest& lr, Node node) override;
void preRegisterTerm(TNode node) override;
diff --git a/src/theory/idl/idl_assertion.cpp b/src/theory/idl/idl_assertion.cpp
deleted file mode 100644
index 1e3905537..000000000
--- a/src/theory/idl/idl_assertion.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/********************* */
-/*! \file idl_assertion.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "theory/idl/idl_assertion.h"
-
-using namespace CVC4;
-using namespace theory;
-using namespace idl;
-
-IDLAssertion::IDLAssertion()
-: d_op(kind::LAST_KIND)
-{}
-
-IDLAssertion::IDLAssertion(TNode node) {
- bool ok = parse(node, 1, false);
- if (!ok) {
- d_x = d_y = TNode::null();
- } else {
- if (d_op == kind::GT) {
- // Turn GT into LT x - y > c is the same as y - x < -c
- std::swap(d_x, d_y);
- d_c = -d_c;
- d_op = kind::LT;
- }
- if (d_op == kind::GEQ) {
- // Turn GT into LT x - y >= c is the same as y - x <= -c
- std::swap(d_x, d_y);
- d_c = -d_c;
- d_op = kind::LEQ;
- }
- if (d_op == kind::LT) {
- // Turn strict into non-strict x - y < c is the same as x - y <= c-1
- d_c = d_c - 1;
- d_op = kind::LEQ;
- }
- }
- d_original = node;
-}
-
-IDLAssertion::IDLAssertion(const IDLAssertion& other)
-: d_x(other.d_x)
-, d_y(other.d_y)
-, d_op(other.d_op)
-, d_c(other.d_c)
-, d_original(other.d_original)
-{}
-
-bool IDLAssertion::propagate(IDLModel& model) const {
- Debug("theory::idl::model") << model << std::endl;
- Assert(ok());
- // Should be d_x - d_y <= d_c, or d_x - d_c <= d_y
- Integer x_value = model.getValue(d_x);
- Integer y_value = model.getValue(d_y);
- if (x_value - y_value > d_c) {
- model.setValue(d_y, x_value - d_c, IDLReason(d_x, d_original));
- Debug("theory::idl::model") << model << std::endl;
- return true;
- } else {
- return false;
- }
-}
-
-void IDLAssertion::toStream(std::ostream& out) const {
- out << "IDL[" << d_x << " - " << d_y << " " << d_op << " " << d_c << "]";
-}
-
-/** Negates the given arithmetic kind */
-static Kind negateOp(Kind op) {
- switch (op) {
- case kind::LT:
- // not (a < b) = (a >= b)
- return kind::GEQ;
- case kind::LEQ:
- // not (a <= b) = (a > b)
- return kind::GT;
- case kind::GT:
- // not (a > b) = (a <= b)
- return kind::LEQ;
- case kind::GEQ:
- // not (a >= b) = (a < b)
- return kind::LT;
- case kind::EQUAL:
- // not (a = b) = (a != b)
- return kind::DISTINCT;
- case kind::DISTINCT:
- // not (a != b) = (a = b)
- return kind::EQUAL;
- default:
- Unreachable();
- break;
- }
- return kind::LAST_KIND;
-}
-
-bool IDLAssertion::parse(TNode node, int c, bool negated) {
-
- // Only unit coefficients allowed
- if (c != 1 && c != -1) {
- return false;
- }
-
- // Assume we're ok
- bool ok = true;
-
- // The kind of the node
- switch(node.getKind()) {
-
- case kind::NOT:
- // We parse the negation
- ok = parse(node[0], c, true);
- // Setup the kind
- if (ok) {
- d_op = negateOp(d_op);
- }
- break;
-
- case kind::EQUAL:
- case kind::LT:
- case kind::LEQ:
- case kind::GT:
- case kind::GEQ: {
- // All relation operators are parsed on both sides
- d_op = node.getKind();
- ok = parse(node[0], c, negated);
- if (ok) {
- ok = parse(node[1],-c, negated);
- }
- break;
- }
-
- case kind::CONST_RATIONAL: {
- // Constants
- Rational m = node.getConst<Rational>();
- if (m.isIntegral()) {
- d_c += m.getNumerator() * (-c);
- } else {
- ok = false;
- }
- break;
- }
- case kind::MULT: {
- // Only unit multiplication of variables
- if (node.getNumChildren() == 2 && node[0].isConst()) {
- Rational a = node[0].getConst<Rational>();
- if (a == 1 || a == -1) {
- ok = parse(node[1], c * a.sgn(), negated);
- } else {
- ok = false;
- }
- } else {
- ok = false;
- }
- break;
- }
-
- case kind::PLUS: {
- for(unsigned i = 0; i < node.getNumChildren(); ++i) {
- ok = parse(node[i], c, negated);
- if(!ok) {
- break;
- }
- }
- break;
- }
-
- case kind::MINUS: {
- ok = parse(node[0], c, negated);
- if (ok) {
- ok = parse(node[1], -c, negated);
- }
- break;
- }
-
- case kind::UMINUS: {
- ok = parse(node[0], -c, negated);
- break;
- }
-
- default: {
- if (c > 0) {
- if (d_x.isNull()) {
- d_x = node;
- } else {
- ok = false;
- }
- } else {
- if (d_y.isNull()) {
- d_y = node;
- } else {
- ok = false;
- }
- }
- break;
- }
- } // End case
-
- // Difference logic OK
- return ok;
-}
diff --git a/src/theory/idl/idl_assertion.h b/src/theory/idl/idl_assertion.h
deleted file mode 100644
index e24fbfc67..000000000
--- a/src/theory/idl/idl_assertion.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/********************* */
-/*! \file idl_assertion.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#pragma once
-
-#include "theory/idl/idl_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace idl {
-
-/**
- * An internal representation of the IDL assertions. Each IDL assertions is
- * of the form (x - y op c) where op is one of (<=, =, !=). IDL assertion
- * can be constructed from an expression.
- */
-class IDLAssertion {
-
- /** The positive variable */
- TNode d_x;
- /** The negative variable */
- TNode d_y;
- /** The relation */
- Kind d_op;
- /** The RHS constant */
- Integer d_c;
-
- /** Original assertion we got this one from */
- TNode d_original;
-
- /** Parses the given node into an assertion, and return true if OK. */
- bool parse(TNode node, int c = 1, bool negated = false);
-
-public:
-
- /** Null assertion */
- IDLAssertion();
- /** Create the assertion from given node */
- IDLAssertion(TNode node);
- /** Copy constructor */
- IDLAssertion(const IDLAssertion& other);
-
- TNode getX() const { return d_x; }
- TNode getY() const { return d_y; }
- Kind getOp() const { return d_op;}
- Integer getC() const { return d_c; }
-
- /**
- * Propagate the constraint using the model. For example, if the constraint
- * is of the form x - y <= -1, and the value of x in the model is 0, then
- *
- * (x - y <= -1) and (x = 0) implies y >= x + 1 = 1
- *
- * If the value of y is less then 1, is is set to 1 and true is returned. If
- * the value of y is 1 or more, than false is return.
- *
- * @return true if value of y was updated
- */
- bool propagate(IDLModel& model) const;
-
- /** Is this constraint proper */
- bool ok() const {
- return !d_x.isNull() || !d_y.isNull();
- }
-
- /** Output to the stream */
- void toStream(std::ostream& out) const;
-};
-
-inline std::ostream& operator << (std::ostream& out, const IDLAssertion& assertion) {
- assertion.toStream(out);
- return out;
-}
-
-}
-}
-}
diff --git a/src/theory/idl/idl_assertion_db.cpp b/src/theory/idl/idl_assertion_db.cpp
deleted file mode 100644
index 865d8b4f5..000000000
--- a/src/theory/idl/idl_assertion_db.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/********************* */
-/*! \file idl_assertion_db.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "theory/idl/idl_assertion_db.h"
-
-using namespace CVC4;
-using namespace theory;
-using namespace idl;
-
-IDLAssertionDB::IDLAssertionDB(context::Context* c)
-: d_assertions(c)
-, d_variableLists(c)
-{}
-
-void IDLAssertionDB::add(const IDLAssertion& assertion, TNode var) {
- // Is there a list for the variable already?
- unsigned previous = -1;
- var_to_unsigned_map::iterator find = d_variableLists.find(var);
- if (find != d_variableLists.end()) {
- previous = (*find).second;
- }
- // Add to the DB
- d_variableLists[var] = d_assertions.size();
- d_assertions.push_back(IDLAssertionListElement(assertion, previous));
-}
-
-IDLAssertionDB::iterator::iterator(IDLAssertionDB& db, TNode var)
-: d_db(db)
-, d_current(-1)
-{
- var_to_unsigned_map::const_iterator find = d_db.d_variableLists.find(var);
- if (find != d_db.d_variableLists.end()) {
- d_current = (*find).second;
- }
-}
-
-void IDLAssertionDB::iterator::next() {
- if (d_current != (unsigned)(-1)) {
- d_current = d_db.d_assertions[d_current].d_previous;
- }
-}
-
-IDLAssertion IDLAssertionDB::iterator::get() const {
- return d_db.d_assertions[d_current].d_assertion;
-}
diff --git a/src/theory/idl/idl_assertion_db.h b/src/theory/idl/idl_assertion_db.h
deleted file mode 100644
index ac87282d9..000000000
--- a/src/theory/idl/idl_assertion_db.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/********************* */
-/*! \file idl_assertion_db.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#pragma once
-
-#include "theory/idl/idl_assertion.h"
-#include "context/cdlist.h"
-
-namespace CVC4 {
-namespace theory {
-namespace idl {
-
-/**
- * Context-dependent database assertions, organized by variable. Each variable
- * can be associated a list of IDL assertions. The list of assertions can
- * be iterated over using the provided iterator class.
- */
-class IDLAssertionDB {
-
- /** Elements of the assertion lists */
- struct IDLAssertionListElement {
- /** The assertion itself */
- IDLAssertion d_assertion;
- /** The index of the previous element (-1 for null) */
- unsigned d_previous;
-
- IDLAssertionListElement(const IDLAssertion& assertion, unsigned previous)
- : d_assertion(assertion), d_previous(previous)
- {}
- };
-
- /** All assertions in a context dependent stack */
- context::CDList<IDLAssertionListElement> d_assertions;
-
- typedef context::CDHashMap<TNode, unsigned, TNodeHashFunction> var_to_unsigned_map;
-
- /** Map from variables to the first element of their list */
- var_to_unsigned_map d_variableLists;
-
-public:
-
- /** Create a new assertion database */
- IDLAssertionDB(context::Context* c);
-
- /** Add a new assertion, attach to the list of the given variable */
- void add(const IDLAssertion& assertion, TNode var);
-
- /** Iteration over the constraints of a variable */
- class iterator {
- /** The database */
- const IDLAssertionDB& d_db;
- /** Index of the current constraint */
- unsigned d_current;
- public:
- /** Construct the iterator for the variable */
- iterator(IDLAssertionDB& db, TNode var);
- /** Is this iterator done */
- bool done() const { return d_current == (unsigned)(-1); }
- /** Next element */
- void next();
- /** Get the assertion */
- IDLAssertion get() const;
- };
-};
-
-}
-}
-}
-
-
-
-
diff --git a/src/theory/idl/idl_model.cpp b/src/theory/idl/idl_model.cpp
deleted file mode 100644
index 4a3426222..000000000
--- a/src/theory/idl/idl_model.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/********************* */
-/*! \file idl_model.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "theory/idl/idl_model.h"
-
-using namespace CVC4;
-using namespace theory;
-using namespace idl;
-
-IDLModel::IDLModel(context::Context* context)
- : d_model(context), d_reason(context)
-{
-}
-
-Integer IDLModel::getValue(TNode var) const
-{
- model_value_map::const_iterator find = d_model.find(var);
- if (find != d_model.end())
- {
- return (*find).second;
- }
- else
- {
- return 0;
- }
-}
-
-void IDLModel::setValue(TNode var, Integer value, IDLReason reason)
-{
- Assert(!reason.d_constraint.isNull());
- d_model[var] = value;
- d_reason[var] = reason;
-}
-
-void IDLModel::getReasonCycle(TNode var, std::vector<TNode>& reasons)
-{
- TNode current = var;
- do
- {
- Debug("theory::idl::model") << "processing: " << var << std::endl;
- Assert(d_reason.find(current) != d_reason.end());
- IDLReason reason = d_reason[current];
- Debug("theory::idl::model")
- << "adding reason: " << reason.d_constraint << std::endl;
- reasons.push_back(reason.d_constraint);
- current = reason.d_x;
- } while (current != var);
-}
-
-void IDLModel::toStream(std::ostream& out) const
-{
- model_value_map::const_iterator it = d_model.begin();
- model_value_map::const_iterator it_end = d_model.end();
- out << "Model[" << std::endl;
- for (; it != it_end; ++it)
- {
- out << (*it).first << " -> " << (*it).second << std::endl;
- }
- out << "]";
-}
diff --git a/src/theory/idl/idl_model.h b/src/theory/idl/idl_model.h
deleted file mode 100644
index 610b90695..000000000
--- a/src/theory/idl/idl_model.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/********************* */
-/*! \file idl_model.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#pragma once
-
-#include "context/cdhashmap.h"
-#include "expr/node.h"
-
-namespace CVC4 {
-namespace theory {
-namespace idl {
-
-/**
- * A reason for a value of a variable in the model is a constraint that implies
- * this value by means of the value of another variable. For example, if the
- * value of x is 0, then the variable x and the constraint (y > 0) are a reason
- * for the y taking the value 1.
- */
-struct IDLReason
-{
- /** The variable of the reason */
- TNode d_x;
- /** The constraint of the reason */
- TNode d_constraint;
-
- IDLReason(TNode x, TNode constraint) : d_x(x), d_constraint(constraint) {}
- IDLReason() {}
-};
-
-/**
- * A model maps variables to integer values and backs them up with reasons.
- * Default values (if not set with setValue) for all variables are 0.
- */
-class IDLModel
-{
- typedef context::CDHashMap<TNode, Integer, TNodeHashFunction> model_value_map;
- typedef context::CDHashMap<TNode, IDLReason, TNodeHashFunction>
- model_reason_map;
-
- /** Values assigned to individual variables */
- model_value_map d_model;
-
- /** Reasons constraining the individual variables */
- model_reason_map d_reason;
-
- public:
- IDLModel(context::Context* context);
-
- /** Get the model value of the variable */
- Integer getValue(TNode var) const;
-
- /** Set the value of the variable */
- void setValue(TNode var, Integer value, IDLReason reason);
-
- /** Get the cycle of reasons behind the variable var */
- void getReasonCycle(TNode var, std::vector<TNode>& reasons);
-
- /** Output to the given stream */
- void toStream(std::ostream& out) const;
-};
-
-inline std::ostream& operator<<(std::ostream& out, const IDLModel& model)
-{
- model.toStream(out);
- return out;
-}
-
-} // namespace idl
-} // namespace theory
-} // namespace CVC4
diff --git a/src/theory/idl/kinds b/src/theory/idl/kinds
deleted file mode 100644
index 6bf0218b0..000000000
--- a/src/theory/idl/kinds
+++ /dev/null
@@ -1,8 +0,0 @@
-# kinds -*- sh -*-
-#
-# For documentation on this file format, please refer to
-# src/theory/builtin/kinds.
-#
-
-alternate THEORY_ARITH "idl" ::CVC4::theory::idl::TheoryIdl "theory/idl/theory_idl.h"
-
diff --git a/src/theory/idl/theory_idl.cpp b/src/theory/idl/theory_idl.cpp
deleted file mode 100644
index f92738bcb..000000000
--- a/src/theory/idl/theory_idl.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/********************* */
-/*! \file theory_idl.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic, Tim King, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "theory/idl/theory_idl.h"
-
-#include <set>
-#include <queue>
-
-#include "options/idl_options.h"
-#include "theory/rewriter.h"
-
-
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace idl {
-
-TheoryIdl::TheoryIdl(context::Context* c, context::UserContext* u,
- OutputChannel& out, Valuation valuation,
- const LogicInfo& logicInfo)
- : Theory(THEORY_ARITH, c, u, out, valuation, logicInfo)
- , d_model(c)
- , d_assertionsDB(c)
-{}
-
-Node TheoryIdl::ppRewrite(TNode atom) {
- if (atom.getKind() == kind::EQUAL && options::idlRewriteEq()) {
- // If the option is turned on, each equality into two inequalities. This in
- // effect removes equalities, and theorefore dis-equalities too.
- Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
- Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
- Node rewritten = Rewriter::rewrite(leq.andNode(geq));
- return rewritten;
- } else {
- return atom;
- }
-}
-
-void TheoryIdl::check(Effort level) {
- if (done() && !fullEffort(level)) {
- return;
- }
-
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- while(!done()) {
-
- // Get the next assertion
- Assertion assertion = get();
- Debug("theory::idl") << "TheoryIdl::check(): processing "
- << assertion.d_assertion << std::endl;
-
- // Convert the assertion into the internal representation
- IDLAssertion idlAssertion(assertion.d_assertion);
- Debug("theory::idl") << "TheoryIdl::check(): got " << idlAssertion << std::endl;
-
- if (idlAssertion.ok()) {
- if (idlAssertion.getOp() == kind::DISTINCT) {
- // We don't handle dis-equalities
- d_out->setIncomplete();
- } else {
- // Process the convex assertions immediately
- bool ok = processAssertion(idlAssertion);
- if (!ok) {
- // In conflict, we're done
- return;
- }
- }
- } else {
- // Not an IDL assertion, set incomplete
- d_out->setIncomplete();
- }
- }
-
-}
-
-bool TheoryIdl::processAssertion(const IDLAssertion& assertion) {
-
- Debug("theory::idl") << "TheoryIdl::processAssertion(" << assertion << ")" << std::endl;
-
- // Add the constraint (x - y op c) to the list assertions of x
- d_assertionsDB.add(assertion, assertion.getX());
-
- // Update the model, if forced by the assertion
- bool y_updated = assertion.propagate(d_model);
-
- // If the value of y was updated, we might need to update further
- if (y_updated) {
-
- std::queue<TNode> queue; // Queue of variables to consider
- std::set<TNode> inQueue; // Current elements of the queue
-
- // Add the first updated variable to the queue
- queue.push(assertion.getY());
- inQueue.insert(assertion.getY());
-
- while (!queue.empty()) {
- // Pop a new variable x off the queue
- TNode x = queue.front();
- queue.pop();
- inQueue.erase(x);
-
- // Go through the constraint (x - y op c), and update values of y
- IDLAssertionDB::iterator it(d_assertionsDB, x);
- while (!it.done()) {
- // Get the assertion and update y
- IDLAssertion x_y_assertion = it.get();
- y_updated = x_y_assertion.propagate(d_model);
- // If updated add to the queue
- if (y_updated) {
- // If the variable that we updated is the same as the first
- // variable that we updated, it's a cycle of updates => conflict
- if (x_y_assertion.getY() == assertion.getX()) {
- std::vector<TNode> reasons;
- d_model.getReasonCycle(x_y_assertion.getY(), reasons);
- // Construct the reason of the conflict
- Node conflict = NodeManager::currentNM()->mkNode(kind::AND, reasons);
- d_out->conflict(conflict);
- return false;
- } else {
- // No cycle, just a model update, so we add to the queue
- TNode y = x_y_assertion.getY();
- if (inQueue.count(y) == 0) {
- queue.push(y);
- inQueue.insert(x_y_assertion.getY());
- }
- }
- }
- // Go to the next constraint
- it.next();
- }
- }
- }
-
- // Everything fine, no conflict
- return true;
-}
-
-} /* namepsace CVC4::theory::idl */
-} /* namepsace CVC4::theory */
-} /* namepsace CVC4 */
diff --git a/src/theory/idl/theory_idl.h b/src/theory/idl/theory_idl.h
deleted file mode 100644
index 1d48d0785..000000000
--- a/src/theory/idl/theory_idl.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/********************* */
-/*! \file theory_idl.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Dejan Jovanovic, Mathias Preiner, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#pragma once
-
-#include "cvc4_private.h"
-
-#include "theory/theory.h"
-#include "theory/idl/idl_model.h"
-#include "theory/idl/idl_assertion_db.h"
-
-namespace CVC4 {
-namespace theory {
-namespace idl {
-
-/**
- * Handles integer difference logic (IDL) constraints.
- */
-class TheoryIdl : public Theory {
-
- /** The current model */
- IDLModel d_model;
-
- /** The asserted constraints, organized by variable */
- IDLAssertionDB d_assertionsDB;
-
- /** Process a new assertion, returns false if in conflict */
- bool processAssertion(const IDLAssertion& assertion);
-
-public:
-
- /** Theory constructor. */
- TheoryIdl(context::Context* c, context::UserContext* u, OutputChannel& out,
- Valuation valuation, const LogicInfo& logicInfo);
-
- /** Pre-processing of input atoms */
- Node ppRewrite(TNode atom) override;
-
- /** Check the assertions for satisfiability */
- void check(Effort effort) override;
-
- /** Identity string */
- std::string identify() const override { return "THEORY_IDL"; }
-
-};/* class TheoryIdl */
-
-}/* CVC4::theory::idl namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/mkrewriter b/src/theory/mkrewriter
index dd5abd219..3c27f1b53 100755
--- a/src/theory/mkrewriter
+++ b/src/theory/mkrewriter
@@ -37,7 +37,6 @@ me=$(basename "$0")
template=$1; shift
rewriter_includes=
-rewrite_init=
pre_rewrite_get_cache=
pre_rewrite_set_cache=
@@ -140,8 +139,6 @@ function rewriter {
rewriter_includes="${rewriter_includes}#include \"$header\"
"
- rewrite_init="${rewrite_init} d_theoryRewriters[${theory_id}].reset(new ${class});
-"
pre_rewrite_attribute_ids="${pre_rewrite_attribute_ids} preids.push_back(expr::attr::AttributeManager::getAttributeId(RewriteAttibute<${theory_id}>::pre_rewrite()));
"
post_rewrite_attribute_ids="${post_rewrite_attribute_ids} postids.push_back(expr::attr::AttributeManager::getAttributeId(RewriteAttibute<${theory_id}>::post_rewrite()));
@@ -257,7 +254,6 @@ for var in \
post_rewrite_get_cache \
pre_rewrite_set_cache \
post_rewrite_set_cache \
- rewrite_init \
pre_rewrite_attribute_ids \
post_rewrite_attribute_ids \
template \
diff --git a/src/theory/mktheorytraits b/src/theory/mktheorytraits
index 8a900e1e7..a87203015 100755
--- a/src/theory/mktheorytraits
+++ b/src/theory/mktheorytraits
@@ -121,12 +121,6 @@ function alternate {
theory_header="$4"
theory_includes="${theory_includes}#include \"$theory_header\"
"
-
- eval "alternate_for_$1=\"\${alternate_for_$1}
- if(engine->useTheoryAlternative(\\\"$2\\\")) {
- engine->addTheory< $3 >($1);
- return;
- }\""
}
function rewriter {
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 231c81bbf..10c5741fe 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -1009,7 +1009,7 @@ bool QuantifiersRewriter::getVarElimLit(Node lit,
{
slv = getVarElimLitBv(lit, args, var);
}
- else if (tt.isString())
+ else if (tt.isStringLike())
{
slv = getVarElimLitString(lit, args, var);
}
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
index d33c72ede..f15b6780c 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
+++ b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
@@ -27,6 +27,7 @@
#include "theory/quantifiers/sygus/term_database_sygus.h"
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
+#include "theory/strings/word.h"
using namespace CVC4::kind;
@@ -405,11 +406,15 @@ void CegGrammarConstructor::mkSygusConstantsForType(TypeNode type,
ops.push_back(nm->mkConst(true));
ops.push_back(nm->mkConst(false));
}
- else if (type.isString())
+ else if (type.isStringLike())
{
- ops.push_back(nm->mkConst(String("")));
- // dummy character "A"
- ops.push_back(nm->mkConst(String("A")));
+ ops.push_back(strings::Word::mkEmptyWord(type));
+ if (type.isString())
+ {
+ // Dummy character "A". This is not necessary for sequences which
+ // have the generic constructor seq.unit.
+ ops.push_back(nm->mkConst(String("A")));
+ }
}
else if (type.isArray() || type.isSet())
{
@@ -449,7 +454,7 @@ void CegGrammarConstructor::collectSygusGrammarTypesFor(
{
collectSygusGrammarTypesFor(range.getSetElementType(), types);
}
- else if (range.isString() )
+ else if (range.isStringLike())
{
// theory of strings shares the integer type
TypeNode intType = NodeManager::currentNM()->integerType();
diff --git a/src/theory/quantifiers/sygus_sampler.cpp b/src/theory/quantifiers/sygus_sampler.cpp
index 28cfa69df..e9c858814 100644
--- a/src/theory/quantifiers/sygus_sampler.cpp
+++ b/src/theory/quantifiers/sygus_sampler.cpp
@@ -560,8 +560,7 @@ Node SygusSampler::getRandomValue(TypeNode tn)
for (unsigned ch : alphas)
{
d_rstring_alphabet.push_back(ch);
- Trace("sygus-sample-str-alpha")
- << " \"" << String::convertUnsignedIntToChar(ch) << "\"";
+ Trace("sygus-sample-str-alpha") << " \\u" << ch;
}
Trace("sygus-sample-str-alpha") << std::endl;
}
diff --git a/src/theory/quantifiers/term_util.cpp b/src/theory/quantifiers/term_util.cpp
index 7f94130f3..cc920f1d7 100644
--- a/src/theory/quantifiers/term_util.cpp
+++ b/src/theory/quantifiers/term_util.cpp
@@ -25,6 +25,7 @@
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/term_enumeration.h"
#include "theory/quantifiers_engine.h"
+#include "theory/strings/word.h"
#include "theory/theory_engine.h"
using namespace std;
@@ -464,11 +465,11 @@ Node TermUtil::mkTypeValue(TypeNode tn, int val)
n = NodeManager::currentNM()->mkConst(false);
}
}
- else if (tn.isString())
+ else if (tn.isStringLike())
{
if (val == 0)
{
- n = NodeManager::currentNM()->mkConst(::CVC4::String(""));
+ n = strings::Word::mkEmptyWord(tn);
}
}
return n;
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 227f4d5b5..e3e3c3824 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -22,6 +22,7 @@
#include "theory/quantifiers/ematching/instantiation_engine.h"
#include "theory/quantifiers/fmf/model_engine.h"
#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
@@ -53,6 +54,11 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output
TheoryQuantifiers::~TheoryQuantifiers() {
}
+std::unique_ptr<TheoryRewriter> TheoryQuantifiers::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new QuantifiersRewriter());
+}
+
void TheoryQuantifiers::finishInit()
{
// quantifiers are not evaluated in getModelValue
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index b5b07f2e6..7efe7419c 100644
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
@@ -39,6 +39,8 @@ class TheoryQuantifiers : public Theory {
const LogicInfo& logicInfo);
~TheoryQuantifiers();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
/** finish initialization */
void finishInit() override;
void preRegisterTerm(TNode n) override;
diff --git a/src/theory/rewriter.cpp b/src/theory/rewriter.cpp
index b3f1e23d7..54b9f319d 100644
--- a/src/theory/rewriter.cpp
+++ b/src/theory/rewriter.cpp
@@ -96,6 +96,12 @@ Node Rewriter::rewrite(TNode node) {
return getInstance().rewriteTo(theoryOf(node), node);
}
+void Rewriter::registerTheoryRewriter(theory::TheoryId tid,
+ std::unique_ptr<TheoryRewriter> trew)
+{
+ getInstance().d_theoryRewriters[tid] = std::move(trew);
+}
+
void Rewriter::registerPreRewrite(
Kind k, std::function<RewriteResponse(RewriteEnvironment*, TNode)> fn)
{
diff --git a/src/theory/rewriter.h b/src/theory/rewriter.h
index f7298e1fb..8a641743b 100644
--- a/src/theory/rewriter.h
+++ b/src/theory/rewriter.h
@@ -63,6 +63,16 @@ class Rewriter {
static void clearCaches();
/**
+ * Registers a theory rewriter with this rewriter. This transfers the
+ * ownership of the theory rewriter to the rewriter.
+ *
+ * @param tid The theory that the theory rewriter should be associated with.
+ * @param trew The theory rewriter to register.
+ */
+ static void registerTheoryRewriter(theory::TheoryId tid,
+ std::unique_ptr<TheoryRewriter> trew);
+
+ /**
* Register a prerewrite for a given kind.
*
* @param k The kind to register a rewrite for.
diff --git a/src/theory/rewriter_tables_template.h b/src/theory/rewriter_tables_template.h
index 1bb03e253..9f6b07389 100644
--- a/src/theory/rewriter_tables_template.h
+++ b/src/theory/rewriter_tables_template.h
@@ -63,8 +63,6 @@ ${post_rewrite_set_cache}
Rewriter::Rewriter()
{
-${rewrite_init}
-
for (size_t i = 0; i < kind::LAST_KIND; ++i)
{
d_preRewriters[i] = nullptr;
@@ -75,7 +73,6 @@ for (size_t i = 0; i < theory::THEORY_LAST; ++i)
{
d_preRewritersEqual[i] = nullptr;
d_postRewritersEqual[i] = nullptr;
- d_theoryRewriters[i]->registerRewrites(this);
}
}
diff --git a/src/theory/sep/theory_sep.cpp b/src/theory/sep/theory_sep.cpp
index 0b6e7a5fb..1d0ad904c 100644
--- a/src/theory/sep/theory_sep.cpp
+++ b/src/theory/sep/theory_sep.cpp
@@ -29,6 +29,7 @@
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
#include "theory/rewriter.h"
+#include "theory/sep/theory_sep_rewriter.h"
#include "theory/theory_model.h"
#include "theory/valuation.h"
@@ -64,6 +65,11 @@ TheorySep::~TheorySep() {
}
}
+std::unique_ptr<TheoryRewriter> TheorySep::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheorySepRewriter());
+}
+
void TheorySep::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
diff --git a/src/theory/sep/theory_sep.h b/src/theory/sep/theory_sep.h
index ae044f6d7..df3294882 100644
--- a/src/theory/sep/theory_sep.h
+++ b/src/theory/sep/theory_sep.h
@@ -66,6 +66,8 @@ class TheorySep : public Theory {
TheorySep(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
~TheorySep();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
std::string identify() const override { return std::string("TheorySep"); }
diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp
index 3b0427ec5..0b9e6d934 100644
--- a/src/theory/sets/theory_sets.cpp
+++ b/src/theory/sets/theory_sets.cpp
@@ -15,8 +15,10 @@
**/
#include "theory/sets/theory_sets.h"
+
#include "options/sets_options.h"
#include "theory/sets/theory_sets_private.h"
+#include "theory/sets/theory_sets_rewriter.h"
#include "theory/theory_model.h"
using namespace CVC4::kind;
@@ -44,6 +46,11 @@ TheorySets::~TheorySets()
// Do not move me to the header. See explanation in the constructor.
}
+std::unique_ptr<TheoryRewriter> TheorySets::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheorySetsRewriter());
+}
+
void TheorySets::finishInit()
{
TheoryModel* tm = d_valuation.getModel();
diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h
index ed2459b32..a55a22600 100644
--- a/src/theory/sets/theory_sets.h
+++ b/src/theory/sets/theory_sets.h
@@ -42,6 +42,8 @@ class TheorySets : public Theory
const LogicInfo& logicInfo);
~TheorySets() override;
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
/** finish initialization */
void finishInit() override;
void addSharedTerm(TNode) override;
diff --git a/src/theory/strings/base_solver.cpp b/src/theory/strings/base_solver.cpp
index 128893cf0..076fc1cc5 100644
--- a/src/theory/strings/base_solver.cpp
+++ b/src/theory/strings/base_solver.cpp
@@ -35,7 +35,6 @@ BaseSolver::BaseSolver(context::Context* c,
d_emptyString = NodeManager::currentNM()->mkConst(::CVC4::String(""));
d_false = NodeManager::currentNM()->mkConst(false);
d_cardSize = utils::getAlphabetCardinality();
- d_type = NodeManager::currentNM()->stringType();
}
BaseSolver::~BaseSolver() {}
@@ -128,7 +127,7 @@ void BaseSolver::checkInit()
}
}
// infer the equality
- d_im.sendInference(exp, n.eqNode(nc), "I_Norm");
+ d_im.sendInference(exp, n.eqNode(nc), Inference::I_NORM);
}
else
{
@@ -173,7 +172,7 @@ void BaseSolver::checkInit()
}
AlwaysAssert(foundNEmpty);
// infer the equality
- d_im.sendInference(exp, n.eqNode(ns), "I_Norm_S");
+ d_im.sendInference(exp, n.eqNode(ns), Inference::I_NORM_S);
}
d_congruent.insert(n);
congruent[k]++;
@@ -254,7 +253,7 @@ void BaseSolver::checkConstantEquivalenceClasses(TermIndex* ti,
if (!n.isNull())
{
// construct the constant
- Node c = utils::mkNConcat(vecc, d_type);
+ Node c = utils::mkNConcat(vecc, n.getType());
if (!d_state.areEqual(n, c))
{
if (Trace.isOn("strings-debug"))
@@ -302,7 +301,7 @@ void BaseSolver::checkConstantEquivalenceClasses(TermIndex* ti,
Assert(countc == vecc.size());
if (d_state.hasTerm(c))
{
- d_im.sendInference(exp, n.eqNode(c), "I_CONST_MERGE");
+ d_im.sendInference(exp, n.eqNode(c), Inference::I_CONST_MERGE);
return;
}
else if (!d_im.hasProcessed())
@@ -334,7 +333,7 @@ void BaseSolver::checkConstantEquivalenceClasses(TermIndex* ti,
exp.push_back(d_eqcToConstExp[nr]);
d_im.addToExplanation(n, d_eqcToConstBase[nr], exp);
}
- d_im.sendInference(exp, d_false, "I_CONST_CONFLICT");
+ d_im.sendInference(exp, d_false, Inference::I_CONST_CONFLICT);
return;
}
else
@@ -484,7 +483,8 @@ void BaseSolver::checkCardinality()
if (!cons.isConst() || !cons.getConst<bool>())
{
std::vector<Node> emptyVec;
- d_im.sendInference(emptyVec, vec_node, cons, "CARDINALITY", true);
+ d_im.sendInference(
+ emptyVec, vec_node, cons, Inference::CARDINALITY, true);
return;
}
}
diff --git a/src/theory/strings/base_solver.h b/src/theory/strings/base_solver.h
index bf223bc0a..3681b49a4 100644
--- a/src/theory/strings/base_solver.h
+++ b/src/theory/strings/base_solver.h
@@ -191,8 +191,6 @@ class BaseSolver
std::map<Kind, TermIndex> d_termIndex;
/** the cardinality of the alphabet */
uint32_t d_cardSize;
- /** The string-like type for this base solver */
- TypeNode d_type;
}; /* class BaseSolver */
} // namespace strings
diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp
index 556ae28c3..3384499a2 100644
--- a/src/theory/strings/core_solver.cpp
+++ b/src/theory/strings/core_solver.cpp
@@ -37,10 +37,8 @@ d_nf_pairs(c)
d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
d_neg_one = NodeManager::currentNM()->mkConst(Rational(-1));
- d_emptyString = Word::mkEmptyWord(CONST_STRING);
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
- d_type = NodeManager::currentNM()->stringType();
}
CoreSolver::~CoreSolver() {
@@ -286,10 +284,11 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
<< "Found endpoint (in a) with non-empty b = " << b
<< ", whose flat form is " << d_flat_form[b] << std::endl;
// endpoint
+ Node emp = Word::mkEmptyWord(a.getType());
std::vector<Node> conc_c;
for (unsigned j = count; j < bsize; j++)
{
- conc_c.push_back(b[d_flat_form_index[b][j]].eqNode(d_emptyString));
+ conc_c.push_back(b[d_flat_form_index[b][j]].eqNode(emp));
}
Assert(!conc_c.empty());
conc = utils::mkAnd(conc_c);
@@ -325,10 +324,11 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
<< "Found endpoint in b = " << b << ", whose flat form is "
<< d_flat_form[b] << std::endl;
// endpoint
+ Node emp = Word::mkEmptyWord(a.getType());
std::vector<Node> conc_c;
for (size_t j = count; j < asize; j++)
{
- conc_c.push_back(a[d_flat_form_index[a][j]].eqNode(d_emptyString));
+ conc_c.push_back(a[d_flat_form_index[a][j]].eqNode(emp));
}
Assert(!conc_c.empty());
conc = utils::mkAnd(conc_c);
@@ -438,11 +438,12 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
}
ssize_t startj = isRev ? jj + 1 : 0;
ssize_t endj = isRev ? c.getNumChildren() : jj;
+ Node emp = Word::mkEmptyWord(a.getType());
for (ssize_t j = startj; j < endj; j++)
{
- if (d_state.areEqual(c[j], d_emptyString))
+ if (d_state.areEqual(c[j], emp))
{
- d_im.addToExplanation(c[j], d_emptyString, exp);
+ d_im.addToExplanation(c[j], emp, exp);
}
}
}
@@ -470,6 +471,7 @@ Node CoreSolver::checkCycles( Node eqc, std::vector< Node >& curr, std::vector<
return eqc;
}else if( std::find( d_strings_eqc.begin(), d_strings_eqc.end(), eqc )==d_strings_eqc.end() ){
curr.push_back( eqc );
+ Node emp = Word::mkEmptyWord(eqc.getType());
//look at all terms in this equivalence class
eq::EqualityEngine* ee = d_state.getEqualityEngine();
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, ee );
@@ -478,22 +480,25 @@ Node CoreSolver::checkCycles( Node eqc, std::vector< Node >& curr, std::vector<
if( !d_bsolver.isCongruent(n) ){
if( n.getKind() == kind::STRING_CONCAT ){
Trace("strings-cycle") << eqc << " check term : " << n << " in " << eqc << std::endl;
- if( eqc!=d_emptyString ){
+ if (eqc != emp)
+ {
d_eqc[eqc].push_back( n );
}
for( unsigned i=0; i<n.getNumChildren(); i++ ){
Node nr = d_state.getRepresentative(n[i]);
- if( eqc==d_emptyString ){
+ if (eqc == emp)
+ {
//for empty eqc, ensure all components are empty
- if( nr!=d_emptyString ){
+ if (nr != emp)
+ {
std::vector<Node> exps;
- exps.push_back(n.eqNode(d_emptyString));
- d_im.sendInference(
- exps, n[i].eqNode(d_emptyString), "I_CYCLE_E");
+ exps.push_back(n.eqNode(emp));
+ d_im.sendInference(exps, n[i].eqNode(emp), "I_CYCLE_E");
return Node::null();
}
}else{
- if( nr!=d_emptyString ){
+ if (nr != emp)
+ {
d_flat_form[n].push_back( nr );
d_flat_form_index[n].push_back( i );
}
@@ -507,10 +512,9 @@ Node CoreSolver::checkCycles( Node eqc, std::vector< Node >& curr, std::vector<
//can infer all other components must be empty
for( unsigned j=0; j<n.getNumChildren(); j++ ){
//take first non-empty
- if (j != i && !d_state.areEqual(n[j], d_emptyString))
+ if (j != i && !d_state.areEqual(n[j], emp))
{
- d_im.sendInference(
- exp, n[j].eqNode(d_emptyString), "I_CYCLE");
+ d_im.sendInference(exp, n[j].eqNode(emp), "I_CYCLE");
return Node::null();
}
}
@@ -551,16 +555,17 @@ void CoreSolver::checkNormalFormsEq()
std::map<Node, Node> eqc_to_exp;
for (const Node& eqc : d_strings_eqc)
{
+ TypeNode stype = eqc.getType();
Trace("strings-process-debug") << "- Verify normal forms are the same for "
<< eqc << std::endl;
- normalizeEquivalenceClass(eqc);
+ normalizeEquivalenceClass(eqc, stype);
Trace("strings-debug") << "Finished normalizing eqc..." << std::endl;
if (d_im.hasProcessed())
{
return;
}
NormalForm& nfe = getNormalForm(eqc);
- Node nf_term = utils::mkNConcat(nfe.d_nf, d_type);
+ Node nf_term = utils::mkNConcat(nfe.d_nf, stype);
std::map<Node, Node>::iterator itn = nf_to_eqc.find(nf_term);
if (itn != nf_to_eqc.end())
{
@@ -602,21 +607,23 @@ void CoreSolver::checkNormalFormsEq()
}
//compute d_normal_forms_(base,exp,exp_depend)[eqc]
-void CoreSolver::normalizeEquivalenceClass( Node eqc ) {
+void CoreSolver::normalizeEquivalenceClass(Node eqc, TypeNode stype)
+{
Trace("strings-process-debug") << "Process equivalence class " << eqc << std::endl;
- if (d_state.areEqual(eqc, d_emptyString))
+ Node emp = Word::mkEmptyWord(stype);
+ if (d_state.areEqual(eqc, emp))
{
#ifdef CVC4_ASSERTIONS
for( unsigned j=0; j<d_eqc[eqc].size(); j++ ){
Node n = d_eqc[eqc][j];
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Assert(d_state.areEqual(n[i], d_emptyString));
+ Assert(d_state.areEqual(n[i], emp));
}
}
#endif
//do nothing
Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : empty." << std::endl;
- d_normal_form[eqc].init(d_emptyString);
+ d_normal_form[eqc].init(emp);
}
else
{
@@ -627,13 +634,13 @@ void CoreSolver::normalizeEquivalenceClass( Node eqc ) {
// map each term to its index in the above vector
std::map<Node, unsigned> term_to_nf_index;
// get the normal forms
- getNormalForms(eqc, normal_forms, term_to_nf_index);
+ getNormalForms(eqc, normal_forms, term_to_nf_index, stype);
if (d_im.hasProcessed())
{
return;
}
// process the normal forms
- processNEqc(normal_forms);
+ processNEqc(normal_forms, stype);
if (d_im.hasProcessed())
{
return;
@@ -679,11 +686,12 @@ Node CoreSolver::getNormalString(Node x, std::vector<Node>& nf_exp)
if (!x.isConst())
{
Node xr = d_state.getRepresentative(x);
+ TypeNode stype = xr.getType();
std::map<Node, NormalForm>::iterator it = d_normal_form.find(xr);
if (it != d_normal_form.end())
{
NormalForm& nf = it->second;
- Node ret = utils::mkNConcat(nf.d_nf, d_type);
+ Node ret = utils::mkNConcat(nf.d_nf, stype);
nf_exp.insert(nf_exp.end(), nf.d_exp.begin(), nf.d_exp.end());
d_im.addToExplanation(x, nf.d_base, nf_exp);
Trace("strings-debug")
@@ -701,16 +709,18 @@ Node CoreSolver::getNormalString(Node x, std::vector<Node>& nf_exp)
Node nc = getNormalString(x[i], nf_exp);
vec_nodes.push_back(nc);
}
- return utils::mkNConcat(vec_nodes, d_type);
+ return utils::mkNConcat(vec_nodes, stype);
}
}
return x;
}
void CoreSolver::getNormalForms(Node eqc,
- std::vector<NormalForm>& normal_forms,
- std::map<Node, unsigned>& term_to_nf_index)
+ std::vector<NormalForm>& normal_forms,
+ std::map<Node, unsigned>& term_to_nf_index,
+ TypeNode stype)
{
+ Node emp = Word::mkEmptyWord(stype);
//constant for equivalence class
Node eqc_non_c = eqc;
Trace("strings-process-debug") << "Get normal forms " << eqc << std::endl;
@@ -719,11 +729,11 @@ void CoreSolver::getNormalForms(Node eqc,
while( !eqc_i.isFinished() ){
Node n = (*eqc_i);
if( !d_bsolver.isCongruent(n) ){
- if (n.getKind() == CONST_STRING || n.getKind() == STRING_CONCAT)
+ if (n.isConst() || n.getKind() == STRING_CONCAT)
{
Trace("strings-process-debug") << "Get Normal Form : Process term " << n << " in eqc " << eqc << std::endl;
NormalForm nf_curr;
- if (n.getKind() == CONST_STRING)
+ if (n.isConst())
{
nf_curr.init(n);
}
@@ -803,8 +813,7 @@ void CoreSolver::getNormalForms(Node eqc,
}
//if not equal to self
std::vector<Node>& currv = nf_curr.d_nf;
- if (currv.size() > 1
- || (currv.size() == 1 && currv[0].getKind() == CONST_STRING))
+ if (currv.size() > 1 || (currv.size() == 1 && currv[0].isConst()))
{
// if in a build with assertions, check that normal form is acyclic
if (Configuration::isAssertionBuild())
@@ -827,7 +836,7 @@ void CoreSolver::getNormalForms(Node eqc,
normal_forms.push_back(nf_curr);
}else{
//this was redundant: combination of self + empty string(s)
- Node nn = currv.size() == 0 ? d_emptyString : currv[0];
+ Node nn = currv.size() == 0 ? emp : currv[0];
Assert(d_state.areEqual(nn, eqc));
}
}else{
@@ -926,7 +935,8 @@ void CoreSolver::getNormalForms(Node eqc,
}
}
-void CoreSolver::processNEqc(std::vector<NormalForm>& normal_forms)
+void CoreSolver::processNEqc(std::vector<NormalForm>& normal_forms,
+ TypeNode stype)
{
//the possible inferences
std::vector< InferInfo > pinfer;
@@ -946,7 +956,7 @@ void CoreSolver::processNEqc(std::vector<NormalForm>& normal_forms)
unsigned rindex = 0;
nfi.reverse();
nfj.reverse();
- processSimpleNEq(nfi, nfj, rindex, true, 0, pinfer);
+ processSimpleNEq(nfi, nfj, rindex, true, 0, pinfer, stype);
nfi.reverse();
nfj.reverse();
if (d_im.hasProcessed())
@@ -957,7 +967,7 @@ void CoreSolver::processNEqc(std::vector<NormalForm>& normal_forms)
//rindex = 0;
unsigned index = 0;
- processSimpleNEq(nfi, nfj, index, false, rindex, pinfer);
+ processSimpleNEq(nfi, nfj, index, false, rindex, pinfer, stype);
if (d_im.hasProcessed())
{
return;
@@ -1001,10 +1011,12 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
unsigned& index,
bool isRev,
unsigned rproc,
- std::vector<InferInfo>& pinfer)
+ std::vector<InferInfo>& pinfer,
+ TypeNode stype)
{
NodeManager* nm = NodeManager::currentNM();
eq::EqualityEngine* ee = d_state.getEqualityEngine();
+ Node emp = Word::mkEmptyWord(stype);
const std::vector<Node>& nfiv = nfi.d_nf;
const std::vector<Node>& nfjv = nfj.d_nf;
@@ -1029,8 +1041,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
while (!d_state.isInConflict() && index_k < (nfkv.size() - rproc))
{
// can infer that this string must be empty
- Node eq = nfkv[index_k].eqNode(d_emptyString);
- Assert(!d_state.areEqual(d_emptyString, nfkv[index_k]));
+ Node eq = nfkv[index_k].eqNode(emp);
+ Assert(!d_state.areEqual(emp, nfkv[index_k]));
d_im.sendInference(curr_exp, eq, Inference::N_ENDPOINT_EMP);
index_k++;
}
@@ -1082,9 +1094,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
d_im.sendInference(lenExp, eq, Inference::N_UNIFY);
break;
}
- else if ((x.getKind() != CONST_STRING && index == nfiv.size() - rproc - 1)
- || (y.getKind() != CONST_STRING
- && index == nfjv.size() - rproc - 1))
+ else if ((!x.isConst() && index == nfiv.size() - rproc - 1)
+ || (!y.isConst() && index == nfjv.size() - rproc - 1))
{
// We have reached the last component in one of the normal forms and it
// is not a constant. Thus, the last component must be equal to the
@@ -1110,7 +1121,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
eqnc.push_back(nfkv[i]);
}
}
- eqn[r] = utils::mkNConcat(eqnc, d_type);
+ eqn[r] = utils::mkNConcat(eqnc, stype);
}
if (!d_state.areEqual(eqn[0], eqn[1]))
{
@@ -1253,15 +1264,15 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
NormalForm& nfnc = x.isConst() ? nfj : nfi;
const std::vector<Node>& nfncv = nfnc.d_nf;
Node nc = nfncv[index];
- Assert(nc.getKind() != CONST_STRING) << "Other string is not constant.";
+ Assert(!nc.isConst()) << "Other string is not constant.";
Assert(nc.getKind() != STRING_CONCAT) << "Other string is not CONCAT.";
- if (!ee->areDisequal(nc, d_emptyString, true))
+ if (!ee->areDisequal(nc, emp, true))
{
// The non-constant side may be equal to the empty string. Split on
// whether it is.
//
// E.g. "abc" ++ ... = nc ++ ... ---> (nc = "") v (nc != "")
- Node eq = nc.eqNode(d_emptyString);
+ Node eq = nc.eqNode(emp);
eq = Rewriter::rewrite(eq);
if (eq.isConst())
{
@@ -1269,7 +1280,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// purify variable for this string to communicate that
// we have inferred whether it is empty.
Node p = d_skCache.mkSkolemCached(nc, SkolemCache::SK_PURIFY, "lsym");
- Node pEq = p.eqNode(d_emptyString);
+ Node pEq = p.eqNode(emp);
// should not be constant
Assert(!Rewriter::rewrite(pEq).isConst());
// infer the purification equality, and the (dis)equality
@@ -1290,7 +1301,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// At this point, we know that `nc` is non-empty, so we add that to our
// explanation.
- Node ncnz = nc.eqNode(d_emptyString).negate();
+ Node ncnz = nc.eqNode(emp).negate();
info.d_ant.push_back(ncnz);
size_t ncIndex = index + 1;
@@ -1302,19 +1313,19 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
//
// E.g. "abc" ++ ... = nc ++ "b" ++ ... ---> nc = "a" ++ k
size_t cIndex = index;
- Node constStr = nfc.collectConstantStringAt(cIndex);
- Assert(!constStr.isNull());
- CVC4::String stra = constStr.getConst<String>();
- CVC4::String strb = nextConstStr.getConst<String>();
+ Node stra = nfc.collectConstantStringAt(cIndex);
+ size_t straLen = Word::getLength(stra);
+ Assert(!stra.isNull());
+ Node strb = nextConstStr;
// Since `nc` is non-empty, we start with character 1
size_t p;
if (isRev)
{
- CVC4::String stra1 = stra.prefix(stra.size() - 1);
- p = stra.size() - stra1.roverlap(strb);
- Trace("strings-csp-debug") << "Compute roverlap : " << constStr << " "
- << nextConstStr << std::endl;
- size_t p2 = stra1.rfind(strb);
+ Node stra1 = Word::prefix(stra, straLen - 1);
+ p = straLen - Word::roverlap(stra1, strb);
+ Trace("strings-csp-debug")
+ << "Compute roverlap : " << stra1 << " " << strb << std::endl;
+ size_t p2 = Word::rfind(stra1, strb);
p = p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
Trace("strings-csp-debug")
<< "roverlap : " << stra1 << " " << strb << " returned " << p
@@ -1322,11 +1333,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
}
else
{
- CVC4::String stra1 = stra.substr(1);
- p = stra.size() - stra1.overlap(strb);
- Trace("strings-csp-debug") << "Compute overlap : " << constStr << " "
- << nextConstStr << std::endl;
- size_t p2 = stra1.find(strb);
+ Node stra1 = Word::substr(stra, 1);
+ p = straLen - Word::overlap(stra1, strb);
+ Trace("strings-csp-debug")
+ << "Compute overlap : " << stra1 << " " << strb << std::endl;
+ size_t p2 = Word::find(stra1, strb);
p = p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
Trace("strings-csp-debug")
<< "overlap : " << stra1 << " " << strb << " returned " << p
@@ -1340,9 +1351,9 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
{
NormalForm::getExplanationForPrefixEq(
nfc, nfnc, cIndex, ncIndex, info.d_ant);
- Node prea = p == stra.size() ? constStr
- : nm->mkConst(isRev ? stra.suffix(p)
- : stra.prefix(p));
+ Node prea = p == straLen ? stra
+ : (isRev ? Word::suffix(stra, p)
+ : Word::prefix(stra, p));
Node sk = d_skCache.mkSkolemCached(
nc,
prea,
@@ -1364,17 +1375,17 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// to start with the first character of the constant.
//
// E.g. "abc" ++ ... = nc ++ ... ---> nc = "a" ++ k
- Node constStr = nfcv[index];
- CVC4::String stra = constStr.getConst<String>();
- Node firstChar = stra.size() == 1 ? constStr
- : nm->mkConst(isRev ? stra.suffix(1)
- : stra.prefix(1));
+ Node stra = nfcv[index];
+ size_t straLen = Word::getLength(stra);
+ Node firstChar = straLen == 1 ? stra
+ : (isRev ? Word::suffix(stra, 1)
+ : Word::prefix(stra, 1));
Node sk = d_skCache.mkSkolemCached(
nc,
isRev ? SkolemCache::SK_ID_VC_SPT_REV : SkolemCache::SK_ID_VC_SPT,
"c_spt");
Trace("strings-csp") << "Const Split: " << firstChar
- << " is removed from " << constStr << " (serial) "
+ << " is removed from " << stra << " (serial) "
<< std::endl;
NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, info.d_ant);
info.d_conc = nc.eqNode(isRev ? utils::mkNConcat(sk, firstChar)
@@ -1391,8 +1402,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
//
// E.g. x ++ ... = y ++ ... ---> (x = y ++ k) v (y = x ++ k)
Assert(d_state.areDisequal(xLenTerm, yLenTerm));
- Assert(x.getKind() != CONST_STRING);
- Assert(y.getKind() != CONST_STRING);
+ Assert(!x.isConst());
+ Assert(!y.isConst());
int32_t lentTestSuccess = -1;
Node lentTestExp;
@@ -1404,7 +1415,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
{
Node t = e == 0 ? x : y;
// do not infer constants are larger than variables
- if (t.getKind() != CONST_STRING)
+ if (!t.isConst())
{
Node lt1 = e == 0 ? xLenTerm : yLenTerm;
Node lt2 = e == 0 ? yLenTerm : xLenTerm;
@@ -1431,8 +1442,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
for (unsigned xory = 0; xory < 2; xory++)
{
Node t = xory == 0 ? x : y;
- Node tnz = x.eqNode(d_emptyString).negate();
- if (ee->areDisequal(x, d_emptyString, true))
+ Node tnz = x.eqNode(emp).negate();
+ if (ee->areDisequal(x, emp, true))
{
info.d_ant.push_back(tnz);
}
@@ -1529,23 +1540,27 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
const std::vector<Node>& veci = nfi.d_nf;
const std::vector<Node>& vecoi = nfj.d_nf;
+ TypeNode stype = veci[loop_index].getType();
+
Trace("strings-loop") << "Detected possible loop for " << veci[loop_index]
<< std::endl;
Trace("strings-loop") << " ... (X)= " << vecoi[index] << std::endl;
Trace("strings-loop") << " ... T(Y.Z)= ";
std::vector<Node> vec_t(veci.begin() + index, veci.begin() + loop_index);
- Node t_yz = utils::mkNConcat(vec_t, d_type);
+ Node t_yz = utils::mkNConcat(vec_t, stype);
Trace("strings-loop") << " (" << t_yz << ")" << std::endl;
Trace("strings-loop") << " ... S(Z.Y)= ";
std::vector<Node> vec_s(vecoi.begin() + index + 1, vecoi.end());
- Node s_zy = utils::mkNConcat(vec_s, d_type);
+ Node s_zy = utils::mkNConcat(vec_s, stype);
Trace("strings-loop") << s_zy << std::endl;
Trace("strings-loop") << " ... R= ";
std::vector<Node> vec_r(veci.begin() + loop_index + 1, veci.end());
- Node r = utils::mkNConcat(vec_r, d_type);
+ Node r = utils::mkNConcat(vec_r, stype);
Trace("strings-loop") << r << std::endl;
- if (s_zy.isConst() && r.isConst() && r != d_emptyString)
+ Node emp = Word::mkEmptyWord(stype);
+
+ if (s_zy.isConst() && r.isConst() && r != emp)
{
int c;
bool flag = true;
@@ -1553,8 +1568,8 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
{
if (c >= 0)
{
- s_zy = nm->mkConst(s_zy.getConst<String>().substr(0, c));
- r = d_emptyString;
+ s_zy = Word::substr(s_zy, 0, c);
+ r = emp;
vec_r.clear();
Trace("strings-loop") << "Strings::Loop: Refactor S(Z.Y)= " << s_zy
<< ", c=" << c << std::endl;
@@ -1574,12 +1589,12 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
for (unsigned i = 0; i < 2; i++)
{
Node t = i == 0 ? veci[loop_index] : t_yz;
- split_eq = t.eqNode(d_emptyString);
+ split_eq = t.eqNode(emp);
Node split_eqr = Rewriter::rewrite(split_eq);
// the equality could rewrite to false
if (!split_eqr.isConst())
{
- if (!d_state.areDisequal(t, d_emptyString))
+ if (!d_state.areDisequal(t, emp))
{
// try to make t equal to empty to avoid loop
info.d_conc = nm->mkNode(kind::OR, split_eq, split_eq.negate());
@@ -1602,10 +1617,10 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
info.d_antn.push_back(ant);
Node str_in_re;
- if (s_zy == t_yz && r == d_emptyString && s_zy.isConst()
+ if (s_zy == t_yz && r == emp && s_zy.isConst()
&& s_zy.getConst<String>().isRepeated())
{
- Node rep_c = nm->mkConst(s_zy.getConst<String>().substr(0, 1));
+ Node rep_c = Word::substr(s_zy, 0, 1);
Trace("strings-loop") << "Special case (X)=" << vecoi[index] << " "
<< std::endl;
Trace("strings-loop") << "... (C)=" << rep_c << " " << std::endl;
@@ -1628,13 +1643,13 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
Node z = Word::substr(t_yz, len, size - len);
Node restr = s_zy;
Node cc;
- if (r != d_emptyString)
+ if (r != emp)
{
std::vector<Node> v2(vec_r);
v2.insert(v2.begin(), y);
v2.insert(v2.begin(), z);
restr = utils::mkNConcat(z, y);
- cc = Rewriter::rewrite(s_zy.eqNode(utils::mkNConcat(v2, d_type)));
+ cc = Rewriter::rewrite(s_zy.eqNode(utils::mkNConcat(v2, stype)));
}
else
{
@@ -1677,16 +1692,16 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
// right
Node sk_w = d_skCache.mkSkolem("w_loop");
Node sk_y = d_skCache.mkSkolem("y_loop");
- d_im.registerLength(sk_y, LENGTH_GEQ_ONE);
+ d_im.registerTermAtomic(sk_y, LENGTH_GEQ_ONE);
Node sk_z = d_skCache.mkSkolem("z_loop");
// t1 * ... * tn = y * z
Node conc1 = t_yz.eqNode(utils::mkNConcat(sk_y, sk_z));
// s1 * ... * sk = z * y * r
vec_r.insert(vec_r.begin(), sk_y);
vec_r.insert(vec_r.begin(), sk_z);
- Node conc2 = s_zy.eqNode(utils::mkNConcat(vec_r, d_type));
+ Node conc2 = s_zy.eqNode(utils::mkNConcat(vec_r, stype));
Node conc3 = vecoi[index].eqNode(utils::mkNConcat(sk_y, sk_w));
- Node restr = r == d_emptyString ? s_zy : utils::mkNConcat(sk_z, sk_y);
+ Node restr = r == emp ? s_zy : utils::mkNConcat(sk_z, sk_y);
str_in_re =
nm->mkNode(kind::STRING_IN_REGEXP,
sk_w,
@@ -1698,7 +1713,6 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
vec_conc.push_back(conc2);
vec_conc.push_back(conc3);
vec_conc.push_back(str_in_re);
- // vec_conc.push_back(sk_y.eqNode(d_emptyString).negate());//by mkskolems
conc = nm->mkNode(kind::AND, vec_conc);
} // normal case
@@ -1745,20 +1759,22 @@ void CoreSolver::processDeq( Node ni, Node nj ) {
Trace("strings-solve-debug") << "...Processing(DEQ) " << i << " " << j << std::endl;
if (!d_state.areEqual(i, j))
{
- Assert(i.getKind() != kind::CONST_STRING
- || j.getKind() != kind::CONST_STRING);
+ Assert(!i.isConst() || !j.isConst());
std::vector< Node > lexp;
Node li = d_state.getLength(i, lexp);
Node lj = d_state.getLength(j, lexp);
if (d_state.areDisequal(li, lj))
{
- if( i.getKind()==kind::CONST_STRING || j.getKind()==kind::CONST_STRING ){
+ if (i.isConst() || j.isConst())
+ {
//check if empty
- Node const_k = i.getKind() == kind::CONST_STRING ? i : j;
- Node nconst_k = i.getKind() == kind::CONST_STRING ? j : i;
- Node lnck = i.getKind() == kind::CONST_STRING ? lj : li;
- if( !ee->areDisequal( nconst_k, d_emptyString, true ) ){
- Node eq = nconst_k.eqNode( d_emptyString );
+ Node const_k = i.isConst() ? i : j;
+ Node nconst_k = i.isConst() ? j : i;
+ Node lnck = i.isConst() ? lj : li;
+ Node emp = Word::mkEmptyWord(nconst_k.getType());
+ if (!ee->areDisequal(nconst_k, emp, true))
+ {
+ Node eq = nconst_k.eqNode(emp);
Node conc = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
d_im.sendInference(d_emptyVec, conc, "D-DISL-Emp-Split");
return;
@@ -1787,7 +1803,7 @@ void CoreSolver::processDeq( Node ni, Node nj ) {
{
Node sk = d_skCache.mkSkolemCached(
nconst_k, SkolemCache::SK_ID_DC_SPT, "dc_spt");
- d_im.registerLength(sk, LENGTH_ONE);
+ d_im.registerTermAtomic(sk, LENGTH_ONE);
Node skr =
d_skCache.mkSkolemCached(nconst_k,
SkolemCache::SK_ID_DC_SPT_REM,
@@ -1800,7 +1816,7 @@ void CoreSolver::processDeq( Node ni, Node nj ) {
antec.end(), nfni.d_exp.begin(), nfni.d_exp.end());
antec.insert(
antec.end(), nfnj.d_exp.begin(), nfnj.d_exp.end());
- antec.push_back( nconst_k.eqNode( d_emptyString ).negate() );
+ antec.push_back(nconst_k.eqNode(emp).negate());
d_im.sendInference(
antec,
nm->mkNode(
@@ -1836,9 +1852,7 @@ void CoreSolver::processDeq( Node ni, Node nj ) {
i, j, SkolemCache::SK_ID_DEQ_Y, "y_dsplit");
Node sk3 = d_skCache.mkSkolemCached(
i, j, SkolemCache::SK_ID_DEQ_Z, "z_dsplit");
- d_im.registerLength(sk3, LENGTH_GEQ_ONE);
- //Node nemp = sk3.eqNode(d_emptyString).negate();
- //conc.push_back(nemp);
+ d_im.registerTermAtomic(sk3, LENGTH_GEQ_ONE);
Node lsk1 = utils::mkNLength(sk1);
conc.push_back( lsk1.eqNode( li ) );
Node lsk2 = utils::mkNLength(sk2);
@@ -1914,6 +1928,8 @@ int CoreSolver::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >&
}
}
}
+ TypeNode stype = ni.getType();
+ Node emp = Word::mkEmptyWord(stype);
NormalForm& nfni = getNormalForm(ni);
NormalForm& nfnj = getNormalForm(nj);
while( index<nfi.size() || index<nfj.size() ) {
@@ -1929,7 +1945,7 @@ int CoreSolver::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >&
std::vector< Node > cc;
std::vector< Node >& nfk = index>=nfi.size() ? nfj : nfi;
for( unsigned index_k=index; index_k<nfk.size(); index_k++ ){
- cc.push_back( nfk[index_k].eqNode( d_emptyString ) );
+ cc.push_back(nfk[index_k].eqNode(emp));
}
Node conc = cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( kind::AND, cc );
conc = Rewriter::rewrite( conc );
@@ -1941,11 +1957,13 @@ int CoreSolver::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >&
Trace("strings-solve-debug") << "...Processing(QED) " << i << " " << j << std::endl;
if (!d_state.areEqual(i, j))
{
- if( i.getKind()==kind::CONST_STRING && j.getKind()==kind::CONST_STRING ) {
+ if (i.isConst() && j.isConst())
+ {
size_t lenI = Word::getLength(i);
size_t lenJ = Word::getLength(j);
unsigned int len_short = lenI < lenJ ? lenI : lenJ;
- bool isSameFix = isRev ? i.getConst<String>().rstrncmp(j.getConst<String>(), len_short): i.getConst<String>().strncmp(j.getConst<String>(), len_short);
+ bool isSameFix = isRev ? Word::rstrncmp(i, j, len_short)
+ : Word::strncmp(i, j, len_short);
if( isSameFix ) {
//same prefix/suffix
//k is the index of the string that is shorter
@@ -2125,6 +2143,7 @@ void CoreSolver::checkNormalFormsDeq()
void CoreSolver::checkLengthsEqc() {
for (unsigned i = 0; i < d_strings_eqc.size(); i++)
{
+ TypeNode stype = d_strings_eqc[i].getType();
NormalForm& nfi = getNormalForm(d_strings_eqc[i]);
Trace("strings-process-debug")
<< "Process length constraints for " << d_strings_eqc[i] << std::endl;
@@ -2141,7 +2160,7 @@ void CoreSolver::checkLengthsEqc() {
// now, check if length normalization has occurred
if (ei->d_normalizedLength.get().isNull())
{
- Node nf = utils::mkNConcat(nfi.d_nf, d_type);
+ Node nf = utils::mkNConcat(nfi.d_nf, stype);
if (Trace.isOn("strings-process-debug"))
{
Trace("strings-process-debug")
@@ -2190,7 +2209,7 @@ void CoreSolver::doInferInfo(const InferInfo& ii)
{
for (const Node& n : sks.second)
{
- d_im.registerLength(n, sks.first);
+ d_im.registerTermAtomic(n, sks.first);
}
}
}
diff --git a/src/theory/strings/core_solver.h b/src/theory/strings/core_solver.h
index c549fa886..3fea5e8de 100644
--- a/src/theory/strings/core_solver.h
+++ b/src/theory/strings/core_solver.h
@@ -218,16 +218,21 @@ class CoreSolver
* current normal form for each term in this equivalence class is identical.
* If it is not, then we add an inference via sendInference and abort the
* call.
+ *
+ * stype is the string-like type of the equivalence class we are processing.
*/
- void normalizeEquivalenceClass(Node n);
+ void normalizeEquivalenceClass(Node n, TypeNode stype);
/**
* For each term in the equivalence class of eqc, this adds data regarding its
* normal form to normal_forms. The map term_to_nf_index maps terms to the
* index in normal_forms where their normal form data is located.
+ *
+ * stype is the string-like type of the equivalence class we are processing.
*/
void getNormalForms(Node eqc,
std::vector<NormalForm>& normal_forms,
- std::map<Node, unsigned>& term_to_nf_index);
+ std::map<Node, unsigned>& term_to_nf_index,
+ TypeNode stype);
/** process normalize equivalence class
*
* This is called when an equivalence class contains a set of terms that
@@ -240,8 +245,10 @@ class CoreSolver
* corresponding to processing the normal form pair in the (forward, reverse)
* directions. Once all possible inferences are recorded, it executes the
* one with highest priority based on the enumeration type Inference.
+ *
+ * stype is the string-like type of the equivalence class we are processing.
*/
- void processNEqc(std::vector<NormalForm>& normal_forms);
+ void processNEqc(std::vector<NormalForm>& normal_forms, TypeNode stype);
/** process simple normal equality
*
* This method is called when two equal terms have normal forms nfi and nfj.
@@ -265,13 +272,16 @@ class CoreSolver
* fowards/backwards traversals of normal forms to ensure that duplicate
* inferences are not processed.
* pinfer: the set of possible inferences we add to.
+ *
+ * stype is the string-like type of the equivalence class we are processing.
*/
void processSimpleNEq(NormalForm& nfi,
NormalForm& nfj,
unsigned& index,
bool isRev,
unsigned rproc,
- std::vector<InferInfo>& pinfer);
+ std::vector<InferInfo>& pinfer,
+ TypeNode stype);
//--------------------------end for checkNormalFormsEq
//--------------------------for checkNormalFormsEq with loops
@@ -325,7 +335,6 @@ class CoreSolver
/** reference to the base solver, used for certain queries */
BaseSolver& d_bsolver;
/** Commonly used constants */
- Node d_emptyString;
Node d_true;
Node d_false;
Node d_zero;
@@ -368,8 +377,6 @@ class CoreSolver
* the argument number of the t1 ... tn they were generated from.
*/
std::map<Node, std::vector<int> > d_flat_form_index;
- /** The string-like type for this solver */
- TypeNode d_type;
}; /* class CoreSolver */
} // namespace strings
diff --git a/src/theory/strings/eqc_info.cpp b/src/theory/strings/eqc_info.cpp
index ab6d473bd..3c0dbc2a7 100644
--- a/src/theory/strings/eqc_info.cpp
+++ b/src/theory/strings/eqc_info.cpp
@@ -15,6 +15,7 @@
#include "theory/strings/eqc_info.h"
#include "theory/strings/theory_strings_utils.h"
+#include "theory/strings/word.h"
using namespace std;
using namespace CVC4::context;
@@ -44,13 +45,13 @@ Node EqcInfo::addEndpointConst(Node t, Node c, bool isSuf)
<< " post=" << isSuf << std::endl;
Node prevC = utils::getConstantEndpoint(prev, isSuf);
Assert(!prevC.isNull());
- Assert(prevC.getKind() == CONST_STRING);
+ Assert(prevC.isConst());
if (c.isNull())
{
c = utils::getConstantEndpoint(t, isSuf);
Assert(!c.isNull());
}
- Assert(c.getKind() == CONST_STRING);
+ Assert(c.isConst());
bool conflict = false;
// if the constant prefixes are different
if (c != prevC)
@@ -59,10 +60,8 @@ Node EqcInfo::addEndpointConst(Node t, Node c, bool isSuf)
Assert(!t.isConst() || !prev.isConst());
Trace("strings-eager-pconf-debug")
<< "Check conflict constants " << prevC << ", " << c << std::endl;
- const String& ps = prevC.getConst<String>();
- const String& cs = c.getConst<String>();
- unsigned pvs = ps.size();
- unsigned cvs = cs.size();
+ size_t pvs = Word::getLength(prevC);
+ size_t cvs = Word::getLength(c);
if (pvs == cvs || (pvs > cvs && t.isConst())
|| (cvs > pvs && prev.isConst()))
{
@@ -73,15 +72,15 @@ Node EqcInfo::addEndpointConst(Node t, Node c, bool isSuf)
}
else
{
- const String& larges = pvs > cvs ? ps : cs;
- const String& smalls = pvs > cvs ? cs : ps;
+ Node larges = pvs > cvs ? prevC : c;
+ Node smalls = pvs > cvs ? c : prevC;
if (isSuf)
{
- conflict = !larges.hasSuffix(smalls);
+ conflict = !Word::hasSuffix(larges, smalls);
}
else
{
- conflict = !larges.hasPrefix(smalls);
+ conflict = !Word::hasPrefix(larges, smalls);
}
}
if (!conflict && (pvs > cvs || prev.isConst()))
diff --git a/src/theory/strings/extf_solver.cpp b/src/theory/strings/extf_solver.cpp
index c586df6dd..a1c04848a 100644
--- a/src/theory/strings/extf_solver.cpp
+++ b/src/theory/strings/extf_solver.cpp
@@ -34,14 +34,16 @@ ExtfSolver::ExtfSolver(context::Context* c,
SkolemCache& skc,
BaseSolver& bs,
CoreSolver& cs,
- ExtTheory* et)
+ ExtTheory* et,
+ SequencesStatistics& stats)
: d_state(s),
d_im(im),
d_skCache(skc),
d_bsolver(bs),
d_csolver(cs),
d_extt(et),
- d_preproc(&skc, u),
+ d_statistics(stats),
+ d_preproc(&skc, u, stats),
d_hasExtf(c, false),
d_extfInferCache(c)
{
@@ -112,7 +114,7 @@ bool ExtfSolver::doReduction(int effort, Node n, bool& isCd)
lexp.push_back(lenx.eqNode(lens));
lexp.push_back(n.negate());
Node xneqs = x.eqNode(s).negate();
- d_im.sendInference(lexp, xneqs, "NEG-CTN-EQL", true);
+ d_im.sendInference(lexp, xneqs, Inference::CTN_NEG_EQUAL, true);
}
// this depends on the current assertions, so we set that this
// inference is context-dependent.
@@ -157,7 +159,7 @@ bool ExtfSolver::doReduction(int effort, Node n, bool& isCd)
Node eq = Rewriter::rewrite(x.eqNode(utils::mkNConcat(sk1, s, sk2)));
std::vector<Node> exp_vec;
exp_vec.push_back(n);
- d_im.sendInference(d_emptyVec, exp_vec, eq, "POS-CTN", true);
+ d_im.sendInference(d_emptyVec, exp_vec, eq, Inference::CTN_POS, true);
Trace("strings-extf-debug")
<< " resolve extf : " << n << " based on positive contain reduction."
<< std::endl;
@@ -183,7 +185,7 @@ bool ExtfSolver::doReduction(int effort, Node n, bool& isCd)
Trace("strings-red-lemma")
<< "Reduction_" << effort << " lemma : " << nnlem << std::endl;
Trace("strings-red-lemma") << "...from " << n << std::endl;
- d_im.sendInference(d_emptyVec, nnlem, "Reduction", true);
+ d_im.sendInference(d_emptyVec, nnlem, Inference::REDUCTION, true);
Trace("strings-extf-debug")
<< " resolve extf : " << n << " based on reduction." << std::endl;
isCd = false;
@@ -362,8 +364,9 @@ void ExtfSolver::checkExtfEval(int effort)
{
Trace("strings-extf")
<< " resolve extf : " << sn << " -> " << nrc << std::endl;
- d_im.sendInference(
- einfo.d_exp, conc, effort == 0 ? "EXTF" : "EXTF-N", true);
+ Inference inf = effort == 0 ? Inference::EXTF : Inference::EXTF_N;
+ d_im.sendInference(einfo.d_exp, conc, inf, true);
+ d_statistics.d_cdSimplifications << n.getKind();
if (d_state.isInConflict())
{
Trace("strings-extf-debug") << " conflict, return." << std::endl;
@@ -513,7 +516,7 @@ void ExtfSolver::checkExtfInference(Node n,
if (d_state.areEqual(conc, d_false))
{
// we are in conflict
- d_im.sendInference(in.d_exp, conc, "CTN_Decompose");
+ d_im.sendInference(in.d_exp, conc, Inference::CTN_DECOMPOSE);
}
else if (d_extt->hasFunctionKind(conc.getKind()))
{
@@ -590,7 +593,7 @@ void ExtfSolver::checkExtfInference(Node n,
exp_c.insert(exp_c.end(),
d_extfInfoTmp[ofrom].d_exp.begin(),
d_extfInfoTmp[ofrom].d_exp.end());
- d_im.sendInference(exp_c, conc, "CTN_Trans");
+ d_im.sendInference(exp_c, conc, Inference::CTN_TRANS);
}
}
}
@@ -645,7 +648,7 @@ Node ExtfSolver::getCurrentSubstitutionFor(int effort,
{
return c;
}
- else if (effort >= 1 && n.getType().isString())
+ else if (effort >= 1 && n.getType().isStringLike())
{
Assert(effort < 3);
// normal forms
diff --git a/src/theory/strings/extf_solver.h b/src/theory/strings/extf_solver.h
index 4c848f430..9ca72fed2 100644
--- a/src/theory/strings/extf_solver.h
+++ b/src/theory/strings/extf_solver.h
@@ -26,6 +26,7 @@
#include "theory/strings/base_solver.h"
#include "theory/strings/core_solver.h"
#include "theory/strings/inference_manager.h"
+#include "theory/strings/sequences_stats.h"
#include "theory/strings/skolem_cache.h"
#include "theory/strings/solver_state.h"
#include "theory/strings/theory_strings_preprocess.h"
@@ -88,7 +89,8 @@ class ExtfSolver
SkolemCache& skc,
BaseSolver& bs,
CoreSolver& cs,
- ExtTheory* et);
+ ExtTheory* et,
+ SequencesStatistics& stats);
~ExtfSolver();
/** check extended functions evaluation
@@ -184,6 +186,8 @@ class ExtfSolver
CoreSolver& d_csolver;
/** the extended theory object for the theory of strings */
ExtTheory* d_extt;
+ /** Reference to the statistics for the theory of strings/sequences. */
+ SequencesStatistics& d_statistics;
/** preprocessing utility, for performing strings reductions */
StringsPreprocess d_preproc;
/** Common constants */
diff --git a/src/theory/strings/infer_info.cpp b/src/theory/strings/infer_info.cpp
index aa7fe8974..1d0ee30ad 100644
--- a/src/theory/strings/infer_info.cpp
+++ b/src/theory/strings/infer_info.cpp
@@ -14,30 +14,54 @@
#include "theory/strings/infer_info.h"
-using namespace CVC4::kind;
-
namespace CVC4 {
namespace theory {
namespace strings {
-std::ostream& operator<<(std::ostream& out, Inference i)
+const char* toString(Inference i)
{
switch (i)
{
- case Inference::N_ENDPOINT_EMP: out << "N_EndpointEmp"; break;
- case Inference::N_UNIFY: out << "N_Unify"; break;
- case Inference::N_ENDPOINT_EQ: out << "N_EndpointEq"; break;
- case Inference::N_CONST: out << "N_Const"; break;
- case Inference::INFER_EMP: out << "Infer-Emp"; break;
- case Inference::SSPLIT_CST_PROP: out << "S-Split(CST-P)-prop"; break;
- case Inference::SSPLIT_VAR_PROP: out << "S-Split(VAR)-prop"; break;
- case Inference::LEN_SPLIT: out << "Len-Split(Len)"; break;
- case Inference::LEN_SPLIT_EMP: out << "Len-Split(Emp)"; break;
- case Inference::SSPLIT_CST: out << "S-Split(CST-P)"; break;
- case Inference::SSPLIT_VAR: out << "S-Split(VAR)"; break;
- case Inference::FLOOP: out << "F-Loop"; break;
- default: out << "?"; break;
+ case Inference::I_NORM_S: return "I_NORM_S";
+ case Inference::I_CONST_MERGE: return "I_CONST_MERGE";
+ case Inference::I_CONST_CONFLICT: return "I_CONST_CONFLICT";
+ case Inference::I_NORM: return "I_NORM";
+ case Inference::CARDINALITY: return "CARDINALITY";
+ case Inference::N_ENDPOINT_EMP: return "N_ENDPOINT_EMP";
+ case Inference::N_UNIFY: return "N_UNIFY";
+ case Inference::N_ENDPOINT_EQ: return "N_ENDPOINT_EQ";
+ case Inference::N_CONST: return "N_CONST";
+ case Inference::INFER_EMP: return "INFER_EMP";
+ case Inference::SSPLIT_CST_PROP: return "SSPLIT_CST_PROP";
+ case Inference::SSPLIT_VAR_PROP: return "SSPLIT_VAR_PROP";
+ case Inference::LEN_SPLIT: return "LEN_SPLIT";
+ case Inference::LEN_SPLIT_EMP: return "LEN_SPLIT_EMP";
+ case Inference::SSPLIT_CST: return "SSPLIT_CST";
+ case Inference::SSPLIT_VAR: return "SSPLIT_VAR";
+ case Inference::FLOOP: return "FLOOP";
+ case Inference::RE_NF_CONFLICT: return "RE_NF_CONFLICT";
+ case Inference::RE_UNFOLD_POS: return "RE_UNFOLD_POS";
+ case Inference::RE_UNFOLD_NEG: return "RE_UNFOLD_NEG";
+ case Inference::RE_INTER_INCLUDE: return "RE_INTER_INCLUDE";
+ case Inference::RE_INTER_CONF: return "RE_INTER_CONF";
+ case Inference::RE_INTER_INFER: return "RE_INTER_INFER";
+ case Inference::RE_DELTA: return "RE_DELTA";
+ case Inference::RE_DELTA_CONF: return "RE_DELTA_CONF";
+ case Inference::RE_DERIVE: return "RE_DERIVE";
+ case Inference::EXTF: return "EXTF";
+ case Inference::EXTF_N: return "EXTF_N";
+ case Inference::CTN_TRANS: return "CTN_TRANS";
+ case Inference::CTN_DECOMPOSE: return "CTN_DECOMPOSE";
+ case Inference::CTN_NEG_EQUAL: return "CTN_NEG_EQUAL";
+ case Inference::CTN_POS: return "CTN_POS";
+ case Inference::REDUCTION: return "REDUCTION";
+ default: return "?";
}
+}
+
+std::ostream& operator<<(std::ostream& out, Inference i)
+{
+ out << toString(i);
return out;
}
diff --git a/src/theory/strings/infer_info.h b/src/theory/strings/infer_info.h
index 9d2f71b53..252445cb4 100644
--- a/src/theory/strings/infer_info.h
+++ b/src/theory/strings/infer_info.h
@@ -19,7 +19,9 @@
#include <map>
#include <vector>
+
#include "expr/node.h"
+#include "util/safe_print.h"
namespace CVC4 {
namespace theory {
@@ -36,6 +38,31 @@ namespace strings {
*/
enum class Inference : uint32_t
{
+ //-------------------------------------- base solver
+ // initial normalize singular
+ // x1 = "" ^ ... ^ x_{i-1} = "" ^ x_{i+1} = "" ^ ... ^ xn = "" =>
+ // x1 ++ ... ++ xn = xi
+ I_NORM_S,
+ // initial constant merge
+ // explain_constant(x, c) => x = c
+ // Above, explain_constant(x,c) is a basic explanation of why x must be equal
+ // to string constant c, which is computed by taking arguments of
+ // concatentation terms that are entailed to be constants. For example:
+ // ( y = "AB" ^ z = "C" ) => y ++ z = "ABC"
+ I_CONST_MERGE,
+ // initial constant conflict
+ // ( explain_constant(x, c1) ^ explain_constant(x, c2) ^ x = y) => false
+ // where c1 != c2.
+ I_CONST_CONFLICT,
+ // initial normalize
+ // Given two concatenation terms, this is applied when we find that they are
+ // equal after e.g. removing strings that are currently empty. For example:
+ // y = "" ^ z = "" => x ++ y = z ++ x
+ I_NORM,
+ // The cardinality inference for strings, see Liang et al CAV 2014.
+ CARDINALITY,
+ //-------------------------------------- end base solver
+ //-------------------------------------- core solver
// Given two normal forms, infers that the remainder one of them has to be
// empty. For example:
// If x1 ++ x2 = y1 and x1 = y1, then x2 = ""
@@ -92,8 +119,94 @@ enum class Inference : uint32_t
// for fresh u, u1, u2.
// This is the rule F-Loop from Figure 5 of Liang et al CAV 2014.
FLOOP,
+ //-------------------------------------- end core solver
+ //-------------------------------------- regexp solver
+ // regular expression normal form conflict
+ // ( x in R ^ x = y ^ rewrite((str.in_re y R)) = false ) => false
+ // where y is the normal form computed for x.
+ RE_NF_CONFLICT,
+ // regular expression unfolding
+ // This is a general class of inferences of the form:
+ // (x in R) => F
+ // where F is formula expressing the next step of checking whether x is in
+ // R. For example:
+ // (x in (R)*) =>
+ // x = "" V x in R V ( x = x1 ++ x2 ++ x3 ^ x1 in R ^ x2 in (R)* ^ x3 in R)
+ RE_UNFOLD_POS,
+ // Same as above, for negative memberships
+ RE_UNFOLD_NEG,
+ // intersection inclusion conflict
+ // (x in R1 ^ ~ x in R2) => false where [[includes(R2,R1)]]
+ // Where includes(R2,R1) is a heuristic check for whether R2 includes R1.
+ RE_INTER_INCLUDE,
+ // intersection conflict, using regexp intersection computation
+ // (x in R1 ^ x in R2) => false where [[intersect(R1, R2) = empty]]
+ RE_INTER_CONF,
+ // intersection inference
+ // (x in R1 ^ y in R2 ^ x = y) => (x in re.inter(R1,R2))
+ RE_INTER_INFER,
+ // regular expression delta
+ // (x = "" ^ x in R) => C
+ // where "" in R holds if and only if C holds.
+ RE_DELTA,
+ // regular expression delta conflict
+ // (x = "" ^ x in R) => false
+ // where R does not accept the empty string.
+ RE_DELTA_CONF,
+ // regular expression derive ???
+ RE_DERIVE,
+ //-------------------------------------- end regexp solver
+ //-------------------------------------- extended function solver
+ // All extended function inferences from context-dependent rewriting produced
+ // by constant substitutions. See Reynolds et al CAV 2017. These are
+ // inferences of the form:
+ // X = Y => f(X) = t when rewrite( f(Y) ) = t
+ // where X = Y is a vector of equalities, where some of Y may be constants.
+ EXTF,
+ // Same as above, for normal form substitutions.
+ EXTF_N,
+ // contain transitive
+ // ( str.contains( s, t ) ^ ~contains( s, r ) ) => ~contains( t, r ).
+ CTN_TRANS,
+ // contain decompose
+ // str.contains( x, str.++( y1, ..., yn ) ) => str.contains( x, yi ) or
+ // ~str.contains( str.++( x1, ..., xn ), y ) => ~str.contains( xi, y )
+ CTN_DECOMPOSE,
+ // contain neg equal
+ // ( len( x ) = len( s ) ^ ~contains( x, s ) ) => x != s
+ CTN_NEG_EQUAL,
+ // contain positive
+ // str.contains( x, y ) => x = w1 ++ y ++ w2
+ // where w1 and w2 are skolem variables.
+ CTN_POS,
+ // All reduction inferences of the form:
+ // f(x1, .., xn) = y ^ P(x1, ..., xn, y)
+ // where f is an extended function, y is the purification variable for
+ // f(x1, .., xn) and P is the reduction predicate for f
+ // (see theory_strings_preprocess).
+ REDUCTION,
+ //-------------------------------------- end extended function solver
NONE,
};
+
+/**
+ * Converts an inference to a string. Note: This function is also used in
+ * `safe_print()`. Changing this functions name or signature will result in
+ * `safe_print()` printing "<unsupported>" instead of the proper strings for
+ * the enum values.
+ *
+ * @param i The inference
+ * @return The name of the inference
+ */
+const char* toString(Inference i);
+
+/**
+ * Writes an inference name to a stream.
+ *
+ * @param out The stream to write to
+ * @param i The inference to write to the stream
+ * @return The stream
+ */
std::ostream& operator<<(std::ostream& out, Inference i);
/**
@@ -175,4 +288,4 @@ class InferInfo
} // namespace theory
} // namespace CVC4
-#endif /* CVC4__THEORY__STRINGS__THEORY_STRINGS_H */
+#endif /* CVC4__THEORY__STRINGS__INFER_INFO_H */
diff --git a/src/theory/strings/inference_manager.cpp b/src/theory/strings/inference_manager.cpp
index eebad2274..cb0c807cc 100644
--- a/src/theory/strings/inference_manager.cpp
+++ b/src/theory/strings/inference_manager.cpp
@@ -20,6 +20,7 @@
#include "theory/rewriter.h"
#include "theory/strings/theory_strings.h"
#include "theory/strings/theory_strings_utils.h"
+#include "theory/strings/word.h"
using namespace std;
using namespace CVC4::context;
@@ -225,6 +226,7 @@ void InferenceManager::sendLemma(Node ant, Node conc, const char* c)
<< std::endl;
Trace("strings-assert")
<< "(assert (not " << ant << ")) ; conflict " << c << std::endl;
+ ++(d_statistics.d_conflictsInfer);
d_out.conflict(ant);
d_state.setConflict();
return;
@@ -368,29 +370,29 @@ Node InferenceManager::getSymbolicDefinition(Node n,
return NodeManager::currentNM()->mkNode(n.getKind(), children);
}
-void InferenceManager::registerLength(Node n)
+Node InferenceManager::registerTerm(Node n)
{
+ Assert(n.getType().isStringLike());
NodeManager* nm = NodeManager::currentNM();
// register length information:
// for variables, split on empty vs positive length
// for concat/const/replace, introduce proxy var and state length relation
Node lsum;
- if (n.getKind() != STRING_CONCAT && n.getKind() != CONST_STRING)
+ if (n.getKind() != STRING_CONCAT && !n.isConst())
{
Node lsumb = nm->mkNode(STRING_LENGTH, n);
lsum = Rewriter::rewrite(lsumb);
// can register length term if it does not rewrite
if (lsum == lsumb)
{
- registerLength(n, LENGTH_SPLIT);
- return;
+ registerTermAtomic(n, LENGTH_SPLIT);
+ return Node::null();
}
}
Node sk = d_skCache.mkSkolemCached(n, SkolemCache::SK_PURIFY, "lsym");
StringsProxyVarAttribute spva;
sk.setAttribute(spva, true);
Node eq = Rewriter::rewrite(sk.eqNode(n));
- Trace("strings-lemma") << "Strings::Lemma LENGTH Term : " << eq << std::endl;
d_proxyVar[n] = sk;
// If we are introducing a proxy for a constant or concat term, we do not
// need to send lemmas about its length, since its length is already
@@ -398,10 +400,8 @@ void InferenceManager::registerLength(Node n)
if (n.isConst() || n.getKind() == STRING_CONCAT)
{
// do not send length lemma for sk.
- registerLength(sk, LENGTH_IGNORE);
+ registerTermAtomic(sk, LENGTH_IGNORE);
}
- Trace("strings-assert") << "(assert " << eq << ")" << std::endl;
- d_out.lemma(eq);
Node skl = nm->mkNode(STRING_LENGTH, sk);
if (n.getKind() == STRING_CONCAT)
{
@@ -422,21 +422,18 @@ void InferenceManager::registerLength(Node n)
lsum = nm->mkNode(PLUS, nodeVec);
lsum = Rewriter::rewrite(lsum);
}
- else if (n.getKind() == CONST_STRING)
+ else if (n.isConst())
{
- lsum = nm->mkConst(Rational(n.getConst<String>().size()));
+ lsum = nm->mkConst(Rational(Word::getLength(n)));
}
Assert(!lsum.isNull());
d_proxyVarToLength[sk] = lsum;
Node ceq = Rewriter::rewrite(skl.eqNode(lsum));
- Trace("strings-lemma") << "Strings::Lemma LENGTH : " << ceq << std::endl;
- Trace("strings-lemma-debug")
- << " prerewrite : " << skl.eqNode(lsum) << std::endl;
- Trace("strings-assert") << "(assert " << ceq << ")" << std::endl;
- d_out.lemma(ceq);
+
+ return nm->mkNode(AND, eq, ceq);
}
-void InferenceManager::registerLength(Node n, LengthStatus s)
+void InferenceManager::registerTermAtomic(Node n, LengthStatus s)
{
if (d_lengthLemmaTermsCache.find(n) != d_lengthLemmaTermsCache.end())
{
@@ -449,7 +446,25 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
// ignore it
return;
}
+ std::map<Node, bool> reqPhase;
+ Node lenLem = getRegisterTermAtomicLemma(n, s, reqPhase);
+ if (!lenLem.isNull())
+ {
+ Trace("strings-lemma") << "Strings::Lemma REGISTER-TERM-ATOMIC : " << lenLem
+ << std::endl;
+ Trace("strings-assert") << "(assert " << lenLem << ")" << std::endl;
+ ++(d_statistics.d_lemmasRegisterTermAtomic);
+ d_out.lemma(lenLem);
+ }
+ for (const std::pair<const Node, bool>& rp : reqPhase)
+ {
+ d_out.requirePhase(rp.first, rp.second);
+ }
+}
+Node InferenceManager::getRegisterTermAtomicLemma(
+ Node n, LengthStatus s, std::map<Node, bool>& reqPhase)
+{
NodeManager* nm = NodeManager::currentNM();
Node n_len = nm->mkNode(kind::STRING_LENGTH, n);
@@ -461,8 +476,7 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
Trace("strings-lemma") << "Strings::Lemma SK-GEQ-ONE : " << len_geq_one
<< std::endl;
Trace("strings-assert") << "(assert " << len_geq_one << ")" << std::endl;
- d_out.lemma(len_geq_one);
- return;
+ return len_geq_one;
}
if (s == LENGTH_ONE)
@@ -471,11 +485,11 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
Trace("strings-lemma") << "Strings::Lemma SK-ONE : " << len_one
<< std::endl;
Trace("strings-assert") << "(assert " << len_one << ")" << std::endl;
- d_out.lemma(len_one);
- return;
+ return len_one;
}
Assert(s == LENGTH_SPLIT);
+ std::vector<Node> lems;
if (options::stringSplitEmp() || !options::stringLenGeqZ())
{
Node n_len_eq_z = n_len.eqNode(d_zero);
@@ -486,7 +500,7 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
if (!case_empty.isConst())
{
Node lem = nm->mkNode(OR, case_empty, case_nempty);
- d_out.lemma(lem);
+ lems.push_back(lem);
Trace("strings-lemma")
<< "Strings::Lemma LENGTH >= 0 : " << lem << std::endl;
// prefer trying the empty case first
@@ -494,10 +508,10 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
// occur in the CNF stream.
n_len_eq_z = Rewriter::rewrite(n_len_eq_z);
Assert(!n_len_eq_z.isConst());
- d_out.requirePhase(n_len_eq_z, true);
+ reqPhase[n_len_eq_z] = true;
n_len_eq_z_2 = Rewriter::rewrite(n_len_eq_z_2);
Assert(!n_len_eq_z_2.isConst());
- d_out.requirePhase(n_len_eq_z_2, true);
+ reqPhase[n_len_eq_z_2] = true;
}
else if (!case_empty.getConst<bool>())
{
@@ -505,7 +519,7 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
Trace("strings-lemma")
<< "Strings::Lemma LENGTH > 0 (non-empty): " << case_nempty
<< std::endl;
- d_out.lemma(case_nempty);
+ lems.push_back(case_nempty);
}
else
{
@@ -521,8 +535,14 @@ void InferenceManager::registerLength(Node n, LengthStatus s)
{
Node n_len_geq = nm->mkNode(kind::GEQ, n_len, d_zero);
n_len_geq = Rewriter::rewrite(n_len_geq);
- d_out.lemma(n_len_geq);
+ lems.push_back(n_len_geq);
+ }
+
+ if (lems.empty())
+ {
+ return Node::null();
}
+ return lems.size() == 1 ? lems[0] : nm->mkNode(AND, lems);
}
void InferenceManager::addToExplanation(Node a,
diff --git a/src/theory/strings/inference_manager.h b/src/theory/strings/inference_manager.h
index c9d483c73..bd2f85d29 100644
--- a/src/theory/strings/inference_manager.h
+++ b/src/theory/strings/inference_manager.h
@@ -210,18 +210,23 @@ class InferenceManager
* exists, otherwise it returns null.
*/
Node getProxyVariableFor(Node n) const;
- /** register length
+ /** register term
+ *
+ * This method is called on non-constant string terms n. It returns a lemma
+ * that should be sent on the output channel of theory of strings upon
+ * registration of this term, or null if no lemma is necessary.
*
- * This method is called on non-constant string terms n. It sends a lemma
- * on the output channel that ensures that the length n satisfies its assigned
- * status (given by argument s).
+ * If n is an atomic term, the method registerTermAtomic is called for n
+ * and s = LENGTH_SPLIT and no lemma is returned.
*/
- void registerLength(Node n);
+ Node registerTerm(Node n);
/** register length
*
- * This method is called on non-constant string terms n. It sends a lemma
- * on the output channel that ensures that the length n satisfies its assigned
- * status (given by argument s).
+ * This method is called on non-constant string terms n that are "atomic"
+ * with respect to length. That is, the rewritten form of len(n) is itself.
+ *
+ * It sends a lemma on the output channel that ensures that the length n
+ * satisfies its assigned status (given by argument s).
*
* If the status is LENGTH_ONE, we send the lemma len( n ) = 1.
*
@@ -238,7 +243,7 @@ class InferenceManager
* In contrast to the above functions, it makes immediate calls to the output
* channel instead of adding them to pending lists.
*/
- void registerLength(Node n, LengthStatus s);
+ void registerTermAtomic(Node n, LengthStatus s);
//---------------------------- end proxy variables and length elaboration
//----------------------------constructing antecedants
@@ -337,6 +342,17 @@ class InferenceManager
* equality engine of this class.
*/
void sendInfer(Node eq_exp, Node eq, const char* c);
+ /**
+ * Get the lemma required for registering the length information for
+ * atomic term n given length status s. For details, see registerTermAtomic.
+ *
+ * Additionally, this method may map literals to a required polarity in the
+ * argument reqPhase, which should be processed by a call to requiredPhase by
+ * the caller of this method.
+ */
+ Node getRegisterTermAtomicLemma(Node n,
+ LengthStatus s,
+ std::map<Node, bool>& reqPhase);
/** the parent theory of strings object */
TheoryStrings& d_parent;
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
index 5b988061b..06f05a8af 100644
--- a/src/theory/strings/kinds
+++ b/src/theory/strings/kinds
@@ -37,15 +37,15 @@ operator STRING_REV 1 "string reverse"
sort STRING_TYPE \
Cardinality::INTEGERS \
well-founded \
- "NodeManager::currentNM()->mkConst(::CVC4::String())" \
- "util/regexp.h" \
+ "NodeManager::currentNM()->mkConst(::CVC4::String())" \
+ "util/string.h" \
"String type"
sort REGEXP_TYPE \
Cardinality::INTEGERS \
well-founded \
- "NodeManager::currentNM()->mkNode(REGEXP_EMPTY, std::vector<Node>() )" \
- "util/regexp.h" \
+ "NodeManager::currentNM()->mkNode(REGEXP_EMPTY, std::vector<Node>() )" \
+ "util/string.h" \
"RegExp type"
enumerator STRING_TYPE \
@@ -55,7 +55,7 @@ enumerator STRING_TYPE \
constant CONST_STRING \
::CVC4::String \
::CVC4::strings::StringHashFunction \
- "util/regexp.h" \
+ "util/string.h" \
"a string of characters"
# equal equal / less than / output
@@ -68,12 +68,25 @@ operator REGEXP_STAR 1 "regexp *"
operator REGEXP_PLUS 1 "regexp +"
operator REGEXP_OPT 1 "regexp ?"
operator REGEXP_RANGE 2 "regexp range"
-operator REGEXP_LOOP 2:3 "regexp loop"
operator REGEXP_COMPLEMENT 1 "regexp complement"
operator REGEXP_EMPTY 0 "regexp empty"
operator REGEXP_SIGMA 0 "regexp all characters"
+constant REGEXP_REPEAT_OP \
+ ::CVC4::RegExpRepeat \
+ ::CVC4::RegExpRepeatHashFunction \
+ "util/regexp.h" \
+ "operator for regular expression repeat; payload is an instance of the CVC4::RegExpRepeat class"
+parameterized REGEXP_REPEAT REGEXP_REPEAT_OP 1 "regular expression repeat; first parameter is a REGEXP_REPEAT_OP, second is a regular expression term"
+
+constant REGEXP_LOOP_OP \
+ ::CVC4::RegExpLoop \
+ ::CVC4::RegExpLoopHashFunction \
+ "util/regexp.h" \
+ "operator for regular expression loop; payload is an instance of the CVC4::RegExpLoop class"
+parameterized REGEXP_LOOP REGEXP_LOOP_OP 1 "regular expression loop; first parameter is a REGEXP_LOOP_OP, second is a regular expression term"
+
#internal
operator REGEXP_RV 1 "regexp rv (internal use only)"
typerule REGEXP_RV "SimpleTypeRule<RRegExp, AInteger>"
@@ -88,7 +101,10 @@ typerule REGEXP_STAR "SimpleTypeRule<RRegExp, ARegExp>"
typerule REGEXP_PLUS "SimpleTypeRule<RRegExp, ARegExp>"
typerule REGEXP_OPT "SimpleTypeRule<RRegExp, ARegExp>"
typerule REGEXP_RANGE ::CVC4::theory::strings::RegExpRangeTypeRule
-typerule REGEXP_LOOP "SimpleTypeRule<RRegExp, ARegExp, AInteger, AOptional<AInteger>>"
+typerule REGEXP_REPEAT_OP "SimpleTypeRule<RBuiltinOperator>"
+typerule REGEXP_REPEAT "SimpleTypeRule<RRegExp, ARegExp>"
+typerule REGEXP_LOOP_OP "SimpleTypeRule<RBuiltinOperator>"
+typerule REGEXP_LOOP "SimpleTypeRule<RRegExp, ARegExp>"
typerule REGEXP_COMPLEMENT "SimpleTypeRule<RRegExp, ARegExp>"
typerule STRING_TO_REGEXP "SimpleTypeRule<RRegExp, AString>"
typerule STRING_IN_REGEXP "SimpleTypeRule<RBool, AString, ARegExp>"
diff --git a/src/theory/strings/normal_form.cpp b/src/theory/strings/normal_form.cpp
index 7a2323d89..05be5f12a 100644
--- a/src/theory/strings/normal_form.cpp
+++ b/src/theory/strings/normal_form.cpp
@@ -18,6 +18,7 @@
#include "options/strings_options.h"
#include "theory/rewriter.h"
#include "theory/strings/theory_strings_utils.h"
+#include "theory/strings/word.h"
using namespace std;
using namespace CVC4::kind;
@@ -28,7 +29,7 @@ namespace strings {
void NormalForm::init(Node base)
{
- Assert(base.getType().isString());
+ Assert(base.getType().isStringLike());
Assert(base.getKind() != STRING_CONCAT);
d_base = base;
d_nf.clear();
@@ -37,7 +38,7 @@ void NormalForm::init(Node base)
d_expDep.clear();
// add to normal form
- if (!base.isConst() || !base.getConst<String>().isEmptyString())
+ if (!base.isConst() || Word::getLength(base) > 0)
{
d_nf.push_back(base);
}
diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp
index d5105a489..d104f3ade 100644
--- a/src/theory/strings/regexp_operation.cpp
+++ b/src/theory/strings/regexp_operation.cpp
@@ -93,15 +93,7 @@ RegExpConstType RegExpOpr::getRegExpConstType(Node r)
{
d_constCache[cur] = RE_C_UNKNOWN;
visit.push_back(cur);
- if (ck == REGEXP_LOOP)
- {
- // only add the first child of loop
- visit.push_back(cur[0]);
- }
- else
- {
- visit.insert(visit.end(), cur.begin(), cur.end());
- }
+ visit.insert(visit.end(), cur.begin(), cur.end());
}
}
else if (it->second == RE_C_UNKNOWN)
@@ -260,7 +252,9 @@ int RegExpOpr::delta( Node r, Node &exp ) {
break;
}
case kind::REGEXP_LOOP: {
- if(r[1] == d_zero) {
+ uint32_t lo = utils::getLoopMinOccurrences(r);
+ if (lo == 0)
+ {
ret = 1;
} else {
ret = delta(r[0], exp);
@@ -501,18 +495,18 @@ int RegExpOpr::derivativeS( Node r, CVC4::String c, Node &retNode ) {
break;
}
case kind::REGEXP_LOOP: {
- if(r[1] == r[2] && r[1] == d_zero) {
+ uint32_t l = utils::getLoopMinOccurrences(r);
+ uint32_t u = utils::getLoopMaxOccurrences(r);
+ if (l == u && l == 0)
+ {
ret = 2;
//retNode = d_emptyRegexp;
} else {
Node dc;
ret = derivativeS(r[0], c, dc);
if(dc==d_emptyRegexp) {
- unsigned l = r[1].getConst<Rational>().getNumerator().toUnsignedInt();
- unsigned u = r[2].getConst<Rational>().getNumerator().toUnsignedInt();
- Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_LOOP, r[0],
- NodeManager::currentNM()->mkConst(CVC4::Rational(l==0? 0 : (l-1))),
- NodeManager::currentNM()->mkConst(CVC4::Rational(u-1)));
+ Node lop = nm->mkConst(RegExpLoop(l == 0 ? 0 : (l - 1), u - 1));
+ Node r2 = nm->mkNode(REGEXP_LOOP, lop, r[0]);
retNode = dc==d_emptySingleton? r2 : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r2 );
} else {
retNode = d_emptyRegexp;
@@ -686,16 +680,16 @@ Node RegExpOpr::derivativeSingle( Node r, CVC4::String c ) {
break;
}
case kind::REGEXP_LOOP: {
- if(r[1] == r[2] && r[1] == d_zero) {
+ uint32_t l = utils::getLoopMinOccurrences(r);
+ uint32_t u = utils::getLoopMaxOccurrences(r);
+ if (l == u || l == 0)
+ {
retNode = d_emptyRegexp;
} else {
Node dc = derivativeSingle(r[0], c);
if(dc != d_emptyRegexp) {
- unsigned l = r[1].getConst<Rational>().getNumerator().toUnsignedInt();
- unsigned u = r[2].getConst<Rational>().getNumerator().toUnsignedInt();
- Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_LOOP, r[0],
- NodeManager::currentNM()->mkConst(CVC4::Rational(l==0? 0 : (l-1))),
- NodeManager::currentNM()->mkConst(CVC4::Rational(u-1)));
+ Node lop = nm->mkConst(RegExpLoop(l == 0 ? 0 : (l - 1), u - 1));
+ Node r2 = nm->mkNode(REGEXP_LOOP, lop, r[0]);
retNode = dc==d_emptySingleton? r2 : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r2 );
} else {
retNode = d_emptyRegexp;
@@ -739,9 +733,7 @@ void RegExpOpr::firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset)
}
case kind::REGEXP_RANGE: {
unsigned a = r[0].getConst<String>().front();
- a = String::convertUnsignedIntToCode(a);
unsigned b = r[1].getConst<String>().front();
- b = String::convertUnsignedIntToCode(b);
Assert(a < b);
Assert(b < std::numeric_limits<unsigned>::max());
for (unsigned c = a; c <= b; c++)
@@ -756,7 +748,6 @@ void RegExpOpr::firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset)
String s = st.getConst<String>();
if(s.size() != 0) {
unsigned sc = s.front();
- sc = String::convertUnsignedIntToCode(sc);
cset.insert(sc);
}
}
@@ -765,7 +756,6 @@ void RegExpOpr::firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset)
if(st[0].isConst()) {
String s = st[0].getConst<String>();
unsigned sc = s.front();
- sc = String::convertUnsignedIntToCode(sc);
cset.insert(sc);
} else {
vset.insert( st[0] );
@@ -854,8 +844,8 @@ void RegExpOpr::firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset)
void RegExpOpr::simplify(Node t, std::vector< Node > &new_nodes, bool polarity) {
Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl;
Assert(t.getKind() == kind::STRING_IN_REGEXP);
- Node str = Rewriter::rewrite(t[0]);
- Node re = Rewriter::rewrite(t[1]);
+ Node str = t[0];
+ Node re = t[1];
if(polarity) {
simplifyPRegExp( str, re, new_nodes );
} else {
@@ -887,13 +877,11 @@ void RegExpOpr::simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes
case kind::REGEXP_RANGE: {
std::vector< Node > vec;
unsigned a = r[0].getConst<String>().front();
- a = String::convertUnsignedIntToCode(a);
unsigned b = r[1].getConst<String>().front();
- b = String::convertUnsignedIntToCode(b);
for (unsigned c = a; c <= b; c++)
{
std::vector<unsigned> tmpVec;
- tmpVec.push_back(String::convertCodeToUnsignedInt(c));
+ tmpVec.push_back(c);
Node tmp = s.eqNode(nm->mkConst(String(tmpVec))).negate();
vec.push_back( tmp );
}
@@ -1522,7 +1510,7 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node >
++it)
{
std::vector<unsigned> cvec;
- cvec.push_back(String::convertCodeToUnsignedInt(*it));
+ cvec.push_back(*it);
String c(cvec);
Trace("regexp-int-debug") << "Try character " << c << " ... " << std::endl;
Node r1l = derivativeSingle(r1, c);
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h
index b9dbedba5..7845b2e00 100644
--- a/src/theory/strings/regexp_operation.h
+++ b/src/theory/strings/regexp_operation.h
@@ -24,10 +24,9 @@
#include <algorithm>
#include <climits>
#include "util/hash.h"
-#include "util/regexp.h"
+#include "util/string.h"
#include "theory/theory.h"
#include "theory/rewriter.h"
-//#include "context/cdhashmap.h"
namespace CVC4 {
namespace theory {
diff --git a/src/theory/strings/regexp_solver.cpp b/src/theory/strings/regexp_solver.cpp
index 30f9c4a73..f6ef92b4d 100644
--- a/src/theory/strings/regexp_solver.cpp
+++ b/src/theory/strings/regexp_solver.cpp
@@ -36,12 +36,14 @@ RegExpSolver::RegExpSolver(TheoryStrings& p,
SolverState& s,
InferenceManager& im,
ExtfSolver& es,
+ SequencesStatistics& stats,
context::Context* c,
context::UserContext* u)
: d_parent(p),
d_state(s),
d_im(im),
d_esolver(es),
+ d_statistics(stats),
d_regexp_ucached(u),
d_regexp_ccached(c),
d_processed_memberships(c)
@@ -160,6 +162,7 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
<< "We have regular expression assertion : " << assertion
<< std::endl;
Node atom = assertion.getKind() == NOT ? assertion[0] : assertion;
+ Assert(atom == Rewriter::rewrite(atom));
bool polarity = assertion.getKind() != NOT;
if (polarity != (e == 0))
{
@@ -222,7 +225,7 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
std::vector<Node> exp_n;
exp_n.push_back(assertion);
Node conc = Node::null();
- d_im.sendInference(nfexp, exp_n, conc, "REGEXP NF Conflict");
+ d_im.sendInference(nfexp, exp_n, conc, Inference::RE_NF_CONFLICT);
addedLemma = true;
break;
}
@@ -268,7 +271,18 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
std::vector<Node> exp_n;
exp_n.push_back(assertion);
Node conc = nvec.size() == 1 ? nvec[0] : nm->mkNode(AND, nvec);
- d_im.sendInference(rnfexp, exp_n, conc, "REGEXP_Unfold");
+ Assert(atom.getKind() == STRING_IN_REGEXP);
+ if (polarity)
+ {
+ d_statistics.d_regexpUnfoldingsPos << atom[1].getKind();
+ }
+ else
+ {
+ d_statistics.d_regexpUnfoldingsNeg << atom[1].getKind();
+ }
+ Inference inf =
+ polarity ? Inference::RE_UNFOLD_POS : Inference::RE_UNFOLD_NEG;
+ d_im.sendInference(rnfexp, exp_n, conc, inf);
addedLemma = true;
if (changed)
{
@@ -387,7 +401,8 @@ bool RegExpSolver::checkEqcInclusion(std::vector<Node>& mems)
}
Node conc;
- d_im.sendInference(vec_nodes, conc, "Intersect inclusion", true);
+ d_im.sendInference(
+ vec_nodes, conc, Inference::RE_INTER_INCLUDE, true);
return false;
}
}
@@ -470,7 +485,7 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
vec_nodes.push_back(mi[0].eqNode(m[0]));
}
Node conc;
- d_im.sendInference(vec_nodes, conc, "INTERSECT CONFLICT", true);
+ d_im.sendInference(vec_nodes, conc, Inference::RE_INTER_CONF, true);
// conflict, return
return false;
}
@@ -490,7 +505,7 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
else
{
// new conclusion
- // (x in R ^ y in R2 ^ x = y) => (x in intersect(R1,R2))
+ // (x in R1 ^ y in R2 ^ x = y) => (x in intersect(R1,R2))
std::vector<Node> vec_nodes;
vec_nodes.push_back(mi);
vec_nodes.push_back(m);
@@ -498,7 +513,7 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
{
vec_nodes.push_back(mi[0].eqNode(m[0]));
}
- d_im.sendInference(vec_nodes, mres, "INTERSECT INFER", true);
+ d_im.sendInference(vec_nodes, mres, Inference::RE_INTER_INFER, true);
// both are reduced
d_parent.getExtTheory()->markReduced(m);
d_parent.getExtTheory()->markReduced(mi);
@@ -522,7 +537,7 @@ bool RegExpSolver::checkPDerivative(
std::vector<Node> exp_n;
exp_n.push_back(atom);
exp_n.push_back(x.eqNode(d_emptyString));
- d_im.sendInference(nf_exp, exp_n, exp, "RegExp Delta");
+ d_im.sendInference(nf_exp, exp_n, exp, Inference::RE_DELTA);
addedLemma = true;
d_regexp_ccached.insert(atom);
return false;
@@ -538,7 +553,7 @@ bool RegExpSolver::checkPDerivative(
exp_n.push_back(atom);
exp_n.push_back(x.eqNode(d_emptyString));
Node conc;
- d_im.sendInference(nf_exp, exp_n, conc, "RegExp Delta CONFLICT");
+ d_im.sendInference(nf_exp, exp_n, conc, Inference::RE_DELTA_CONF);
addedLemma = true;
d_regexp_ccached.insert(atom);
return false;
@@ -628,7 +643,7 @@ bool RegExpSolver::deriveRegExp(Node x,
}
std::vector<Node> exp_n;
exp_n.push_back(atom);
- d_im.sendInference(ant, exp_n, conc, "RegExp-Derive");
+ d_im.sendInference(ant, exp_n, conc, Inference::RE_DERIVE);
return true;
}
return false;
diff --git a/src/theory/strings/regexp_solver.h b/src/theory/strings/regexp_solver.h
index 4880af905..1d065181b 100644
--- a/src/theory/strings/regexp_solver.h
+++ b/src/theory/strings/regexp_solver.h
@@ -26,8 +26,9 @@
#include "theory/strings/extf_solver.h"
#include "theory/strings/inference_manager.h"
#include "theory/strings/regexp_operation.h"
+#include "theory/strings/sequences_stats.h"
#include "theory/strings/solver_state.h"
-#include "util/regexp.h"
+#include "util/string.h"
namespace CVC4 {
namespace theory {
@@ -49,6 +50,7 @@ class RegExpSolver
SolverState& s,
InferenceManager& im,
ExtfSolver& es,
+ SequencesStatistics& stats,
context::Context* c,
context::UserContext* u);
~RegExpSolver() {}
@@ -119,6 +121,8 @@ class RegExpSolver
InferenceManager& d_im;
/** reference to the extended function solver of the parent */
ExtfSolver& d_esolver;
+ /** Reference to the statistics for the theory of strings/sequences. */
+ SequencesStatistics& d_statistics;
// check membership constraints
Node mkAnd(Node c1, Node c2);
/**
diff --git a/src/theory/strings/rewrites.cpp b/src/theory/strings/rewrites.cpp
new file mode 100644
index 000000000..f1a818bf3
--- /dev/null
+++ b/src/theory/strings/rewrites.cpp
@@ -0,0 +1,214 @@
+/********************* */
+/*! \file rewrites.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of inference information utility.
+ **/
+
+#include "theory/strings/rewrites.h"
+
+#include <iostream>
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+const char* toString(Rewrite r)
+{
+ switch (r)
+ {
+ case Rewrite::CTN_COMPONENT: return "CTN_COMPONENT";
+ case Rewrite::CTN_CONCAT_CHAR: return "CTN_CONCAT_CHAR";
+ case Rewrite::CTN_CONST: return "CTN_CONST";
+ case Rewrite::CTN_EQ: return "CTN_EQ";
+ case Rewrite::CTN_LEN_INEQ: return "CTN_LEN_INEQ";
+ case Rewrite::CTN_LEN_INEQ_NSTRICT: return "CTN_LEN_INEQ_NSTRICT";
+ case Rewrite::CTN_LHS_EMPTYSTR: return "CTN_LHS_EMPTYSTR";
+ case Rewrite::CTN_MSET_NSS: return "CTN_MSET_NSS";
+ case Rewrite::CTN_NCONST_CTN_CONCAT: return "CTN_NCONST_CTN_CONCAT";
+ case Rewrite::CTN_REPL: return "CTN_REPL";
+ case Rewrite::CTN_REPL_CHAR: return "CTN_REPL_CHAR";
+ case Rewrite::CTN_REPL_CNSTS_TO_CTN: return "CTN_REPL_CNSTS_TO_CTN";
+ case Rewrite::CTN_REPL_EMPTY: return "CTN_REPL_EMPTY";
+ case Rewrite::CTN_REPL_LEN_ONE_TO_CTN: return "CTN_REPL_LEN_ONE_TO_CTN";
+ case Rewrite::CTN_REPL_SELF: return "CTN_REPL_SELF";
+ case Rewrite::CTN_REPL_SIMP_REPL: return "CTN_REPL_SIMP_REPL";
+ case Rewrite::CTN_REPL_TO_CTN: return "CTN_REPL_TO_CTN";
+ case Rewrite::CTN_REPL_TO_CTN_DISJ: return "CTN_REPL_TO_CTN_DISJ";
+ case Rewrite::CTN_RHS_EMPTYSTR: return "CTN_RHS_EMPTYSTR";
+ case Rewrite::CTN_RPL_NON_CTN: return "CTN_RPL_NON_CTN";
+ case Rewrite::CTN_SPLIT: return "CTN_SPLIT";
+ case Rewrite::CTN_SPLIT_ONES: return "CTN_SPLIT_ONES";
+ case Rewrite::CTN_STRIP_ENDPT: return "CTN_STRIP_ENDPT";
+ case Rewrite::CTN_SUBSTR: return "CTN_SUBSTR";
+ case Rewrite::EQ_LEN_DEQ: return "EQ_LEN_DEQ";
+ case Rewrite::EQ_NCTN: return "EQ_NCTN";
+ case Rewrite::EQ_NFIX: return "EQ_NFIX";
+ case Rewrite::FROM_CODE_EVAL: return "FROM_CODE_EVAL";
+ case Rewrite::IDOF_DEF_CTN: return "IDOF_DEF_CTN";
+ case Rewrite::IDOF_EMP_IDOF: return "IDOF_EMP_IDOF";
+ case Rewrite::IDOF_EQ_CST_START: return "IDOF_EQ_CST_START";
+ case Rewrite::IDOF_EQ_NORM: return "IDOF_EQ_NORM";
+ case Rewrite::IDOF_EQ_NSTART: return "IDOF_EQ_NSTART";
+ case Rewrite::IDOF_FIND: return "IDOF_FIND";
+ case Rewrite::IDOF_LEN: return "IDOF_LEN";
+ case Rewrite::IDOF_MAX: return "IDOF_MAX";
+ case Rewrite::IDOF_NCTN: return "IDOF_NCTN";
+ case Rewrite::IDOF_NEG: return "IDOF_NEG";
+ case Rewrite::IDOF_NFIND: return "IDOF_NFIND";
+ case Rewrite::IDOF_NORM_PREFIX: return "IDOF_NORM_PREFIX";
+ case Rewrite::IDOF_PULL_ENDPT: return "IDOF_PULL_ENDPT";
+ case Rewrite::IDOF_STRIP_CNST_ENDPTS: return "IDOF_STRIP_CNST_ENDPTS";
+ case Rewrite::IDOF_STRIP_SYM_LEN: return "IDOF_STRIP_SYM_LEN";
+ case Rewrite::ITOS_EVAL: return "ITOS_EVAL";
+ case Rewrite::RE_AND_EMPTY: return "RE_AND_EMPTY";
+ case Rewrite::RE_ANDOR_FLATTEN: return "RE_ANDOR_FLATTEN";
+ case Rewrite::RE_CHAR_IN_STR_STAR: return "RE_CHAR_IN_STR_STAR";
+ case Rewrite::RE_CONCAT: return "RE_CONCAT";
+ case Rewrite::RE_CONCAT_FLATTEN: return "RE_CONCAT_FLATTEN";
+ case Rewrite::RE_CONCAT_OPT: return "RE_CONCAT_OPT";
+ case Rewrite::RE_CONCAT_PURE_ALLCHAR: return "RE_CONCAT_PURE_ALLCHAR";
+ case Rewrite::RE_CONCAT_TO_CONTAINS: return "RE_CONCAT_TO_CONTAINS";
+ case Rewrite::RE_EMPTY_IN_STR_STAR: return "RE_EMPTY_IN_STR_STAR";
+ case Rewrite::RE_IN_DIST_CHAR_STAR: return "RE_IN_DIST_CHAR_STAR";
+ case Rewrite::RE_IN_SIGMA_STAR: return "RE_IN_SIGMA_STAR";
+ case Rewrite::RE_LOOP: return "RE_LOOP";
+ case Rewrite::RE_LOOP_STAR: return "RE_LOOP_STAR";
+ case Rewrite::RE_OR_ALL: return "RE_OR_ALL";
+ case Rewrite::RE_SIMPLE_CONSUME: return "RE_SIMPLE_CONSUME";
+ case Rewrite::RE_STAR_EMPTY: return "RE_STAR_EMPTY";
+ case Rewrite::RE_STAR_EMPTY_STRING: return "RE_STAR_EMPTY_STRING";
+ case Rewrite::RE_STAR_NESTED_STAR: return "RE_STAR_NESTED_STAR";
+ case Rewrite::RE_STAR_UNION: return "RE_STAR_UNION";
+ case Rewrite::REPL_CHAR_NCONTRIB_FIND: return "REPL_CHAR_NCONTRIB_FIND";
+ case Rewrite::REPL_DUAL_REPL_ITE: return "REPL_DUAL_REPL_ITE";
+ case Rewrite::REPL_REPL_SHORT_CIRCUIT: return "REPL_REPL_SHORT_CIRCUIT";
+ case Rewrite::REPL_REPL2_INV: return "REPL_REPL2_INV";
+ case Rewrite::REPL_REPL2_INV_ID: return "REPL_REPL2_INV_ID";
+ case Rewrite::REPL_REPL3_INV: return "REPL_REPL3_INV";
+ case Rewrite::REPL_REPL3_INV_ID: return "REPL_REPL3_INV_ID";
+ case Rewrite::REPL_SUBST_IDX: return "REPL_SUBST_IDX";
+ case Rewrite::REPLALL_CONST: return "REPLALL_CONST";
+ case Rewrite::REPLALL_EMPTY_FIND: return "REPLALL_EMPTY_FIND";
+ case Rewrite::RPL_CCTN: return "RPL_CCTN";
+ case Rewrite::RPL_CCTN_RPL: return "RPL_CCTN_RPL";
+ case Rewrite::RPL_CNTS_SUBSTS: return "RPL_CNTS_SUBSTS";
+ case Rewrite::RPL_CONST_FIND: return "RPL_CONST_FIND";
+ case Rewrite::RPL_CONST_NFIND: return "RPL_CONST_NFIND";
+ case Rewrite::RPL_EMP_CNTS_SUBSTS: return "RPL_EMP_CNTS_SUBSTS";
+ case Rewrite::RPL_ID: return "RPL_ID";
+ case Rewrite::RPL_NCTN: return "RPL_NCTN";
+ case Rewrite::RPL_PULL_ENDPT: return "RPL_PULL_ENDPT";
+ case Rewrite::RPL_REPLACE: return "RPL_REPLACE";
+ case Rewrite::RPL_RPL_EMPTY: return "RPL_RPL_EMPTY";
+ case Rewrite::RPL_RPL_LEN_ID: return "RPL_RPL_LEN_ID";
+ case Rewrite::RPL_X_Y_X_SIMP: return "RPL_X_Y_X_SIMP";
+ case Rewrite::SPLIT_EQ: return "SPLIT_EQ";
+ case Rewrite::SPLIT_EQ_STRIP_L: return "SPLIT_EQ_STRIP_L";
+ case Rewrite::SPLIT_EQ_STRIP_R: return "SPLIT_EQ_STRIP_R";
+ case Rewrite::SS_COMBINE: return "SS_COMBINE";
+ case Rewrite::SS_CONST_END_OOB: return "SS_CONST_END_OOB";
+ case Rewrite::SS_CONST_LEN_MAX_OOB: return "SS_CONST_LEN_MAX_OOB";
+ case Rewrite::SS_CONST_LEN_NON_POS: return "SS_CONST_LEN_NON_POS";
+ case Rewrite::SS_CONST_SS: return "SS_CONST_SS";
+ case Rewrite::SS_CONST_START_MAX_OOB: return "SS_CONST_START_MAX_OOB";
+ case Rewrite::SS_CONST_START_NEG: return "SS_CONST_START_NEG";
+ case Rewrite::SS_CONST_START_OOB: return "SS_CONST_START_OOB";
+ case Rewrite::SS_EMPTYSTR: return "SS_EMPTYSTR";
+ case Rewrite::SS_END_PT_NORM: return "SS_END_PT_NORM";
+ case Rewrite::SS_GEQ_ZERO_START_ENTAILS_EMP_S:
+ return "SS_GEQ_ZERO_START_ENTAILS_EMP_S";
+ case Rewrite::SS_LEN_INCLUDE: return "SS_LEN_INCLUDE";
+ case Rewrite::SS_LEN_NON_POS: return "SS_LEN_NON_POS";
+ case Rewrite::SS_LEN_ONE_Z_Z: return "SS_LEN_ONE_Z_Z";
+ case Rewrite::SS_NON_ZERO_LEN_ENTAILS_OOB:
+ return "SS_NON_ZERO_LEN_ENTAILS_OOB";
+ case Rewrite::SS_START_ENTAILS_ZERO_LEN: return "SS_START_ENTAILS_ZERO_LEN";
+ case Rewrite::SS_START_GEQ_LEN: return "SS_START_GEQ_LEN";
+ case Rewrite::SS_START_NEG: return "SS_START_NEG";
+ case Rewrite::SS_STRIP_END_PT: return "SS_STRIP_END_PT";
+ case Rewrite::SS_STRIP_START_PT: return "SS_STRIP_START_PT";
+ case Rewrite::STOI_CONCAT_NONNUM: return "STOI_CONCAT_NONNUM";
+ case Rewrite::STOI_EVAL: return "STOI_EVAL";
+ case Rewrite::STR_CONV_CONST: return "STR_CONV_CONST";
+ case Rewrite::STR_CONV_IDEM: return "STR_CONV_IDEM";
+ case Rewrite::STR_CONV_ITOS: return "STR_CONV_ITOS";
+ case Rewrite::STR_CONV_MINSCOPE_CONCAT: return "STR_CONV_MINSCOPE_CONCAT";
+ case Rewrite::STR_EMP_REPL_EMP: return "STR_EMP_REPL_EMP";
+ case Rewrite::STR_EMP_REPL_EMP_R: return "STR_EMP_REPL_EMP_R";
+ case Rewrite::STR_EMP_REPL_X_Y_X: return "STR_EMP_REPL_X_Y_X";
+ case Rewrite::STR_EMP_SUBSTR_ELIM: return "STR_EMP_SUBSTR_ELIM";
+ case Rewrite::STR_EMP_SUBSTR_LEQ_LEN: return "STR_EMP_SUBSTR_LEQ_LEN";
+ case Rewrite::STR_EMP_SUBSTR_LEQ_Z: return "STR_EMP_SUBSTR_LEQ_Z";
+ case Rewrite::STR_EQ_CONJ_LEN_ENTAIL: return "STR_EQ_CONJ_LEN_ENTAIL";
+ case Rewrite::STR_EQ_CONST_NHOMOG: return "STR_EQ_CONST_NHOMOG";
+ case Rewrite::STR_EQ_HOMOG_CONST: return "STR_EQ_HOMOG_CONST";
+ case Rewrite::STR_EQ_REPL_EMP: return "STR_EQ_REPL_EMP";
+ case Rewrite::STR_EQ_REPL_NOT_CTN: return "STR_EQ_REPL_NOT_CTN";
+ case Rewrite::STR_EQ_REPL_TO_DIS: return "STR_EQ_REPL_TO_DIS";
+ case Rewrite::STR_EQ_REPL_TO_EQ: return "STR_EQ_REPL_TO_EQ";
+ case Rewrite::STR_EQ_UNIFY: return "STR_EQ_UNIFY";
+ case Rewrite::STR_LEQ_CPREFIX: return "STR_LEQ_CPREFIX";
+ case Rewrite::STR_LEQ_EMPTY: return "STR_LEQ_EMPTY";
+ case Rewrite::STR_LEQ_EVAL: return "STR_LEQ_EVAL";
+ case Rewrite::STR_LEQ_ID: return "STR_LEQ_ID";
+ case Rewrite::STR_REV_CONST: return "STR_REV_CONST";
+ case Rewrite::STR_REV_IDEM: return "STR_REV_IDEM";
+ case Rewrite::STR_REV_MINSCOPE_CONCAT: return "STR_REV_MINSCOPE_CONCAT";
+ case Rewrite::SUBSTR_REPL_SWAP: return "SUBSTR_REPL_SWAP";
+ case Rewrite::SUF_PREFIX_CONST: return "SUF_PREFIX_CONST";
+ case Rewrite::SUF_PREFIX_CTN: return "SUF_PREFIX_CTN";
+ case Rewrite::SUF_PREFIX_EMPTY: return "SUF_PREFIX_EMPTY";
+ case Rewrite::SUF_PREFIX_EMPTY_CONST: return "SUF_PREFIX_EMPTY_CONST";
+ case Rewrite::SUF_PREFIX_EQ: return "SUF_PREFIX_EQ";
+ case Rewrite::SUF_PREFIX_TO_EQS: return "SUF_PREFIX_TO_EQS";
+ case Rewrite::TO_CODE_EVAL: return "TO_CODE_EVAL";
+ case Rewrite::EQ_REFL: return "EQ_REFL";
+ case Rewrite::EQ_CONST_FALSE: return "EQ_CONST_FALSE";
+ case Rewrite::EQ_SYM: return "EQ_SYM";
+ case Rewrite::CONCAT_NORM: return "CONCAT_NORM";
+ case Rewrite::IS_DIGIT_ELIM: return "IS_DIGIT_ELIM";
+ case Rewrite::RE_CONCAT_EMPTY: return "RE_CONCAT_EMPTY";
+ case Rewrite::RE_CONSUME_CCONF: return "RE_CONSUME_CCONF";
+ case Rewrite::RE_CONSUME_S: return "RE_CONSUME_S";
+ case Rewrite::RE_CONSUME_S_CCONF: return "RE_CONSUME_S_CCONF";
+ case Rewrite::RE_CONSUME_S_FULL: return "RE_CONSUME_S_FULL";
+ case Rewrite::RE_IN_EMPTY: return "RE_IN_EMPTY";
+ case Rewrite::RE_IN_SIGMA: return "RE_IN_SIGMA";
+ case Rewrite::RE_IN_EVAL: return "RE_IN_EVAL";
+ case Rewrite::RE_IN_COMPLEMENT: return "RE_IN_COMPLEMENT";
+ case Rewrite::RE_IN_RANGE: return "RE_IN_RANGE";
+ case Rewrite::RE_IN_CSTRING: return "RE_IN_CSTRING";
+ case Rewrite::RE_IN_ANDOR: return "RE_IN_ANDOR";
+ case Rewrite::RE_REPEAT_ELIM: return "RE_REPEAT_ELIM";
+ case Rewrite::SUF_PREFIX_ELIM: return "SUF_PREFIX_ELIM";
+ case Rewrite::STR_LT_ELIM: return "STR_LT_ELIM";
+ case Rewrite::RE_RANGE_SINGLE: return "RE_RANGE_SINGLE";
+ case Rewrite::RE_OPT_ELIM: return "RE_OPT_ELIM";
+ case Rewrite::RE_PLUS_ELIM: return "RE_PLUS_ELIM";
+ case Rewrite::RE_DIFF_ELIM: return "RE_DIFF_ELIM";
+ case Rewrite::LEN_EVAL: return "LEN_EVAL";
+ case Rewrite::LEN_CONCAT: return "LEN_CONCAT";
+ case Rewrite::LEN_REPL_INV: return "LEN_REPL_INV";
+ case Rewrite::LEN_CONV_INV: return "LEN_CONV_INV";
+ case Rewrite::CHARAT_ELIM: return "CHARAT_ELIM";
+ default: return "?";
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, Rewrite r)
+{
+ out << toString(r);
+ return out;
+}
+
+} // namespace strings
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/strings/rewrites.h b/src/theory/strings/rewrites.h
new file mode 100644
index 000000000..cfa8c8448
--- /dev/null
+++ b/src/theory/strings/rewrites.h
@@ -0,0 +1,231 @@
+/********************* */
+/*! \file rewrites.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Type for rewrites for strings.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__STRINGS__REWRITES_H
+#define CVC4__THEORY__STRINGS__REWRITES_H
+
+#include <iosfwd>
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+/** Types of rewrites used by strings
+ *
+ * This rewrites are documented where they are used in the rewriter.
+ */
+enum class Rewrite : uint32_t
+{
+ CTN_COMPONENT,
+ CTN_CONCAT_CHAR,
+ CTN_CONST,
+ CTN_EQ,
+ CTN_LEN_INEQ,
+ CTN_LEN_INEQ_NSTRICT,
+ CTN_LHS_EMPTYSTR,
+ CTN_MSET_NSS,
+ CTN_NCONST_CTN_CONCAT,
+ CTN_REPL,
+ CTN_REPL_CHAR,
+ CTN_REPL_CNSTS_TO_CTN,
+ CTN_REPL_EMPTY,
+ CTN_REPL_LEN_ONE_TO_CTN,
+ CTN_REPL_SELF,
+ CTN_REPL_SIMP_REPL,
+ CTN_REPL_TO_CTN,
+ CTN_REPL_TO_CTN_DISJ,
+ CTN_RHS_EMPTYSTR,
+ CTN_RPL_NON_CTN,
+ CTN_SPLIT,
+ CTN_SPLIT_ONES,
+ CTN_STRIP_ENDPT,
+ CTN_SUBSTR,
+ EQ_LEN_DEQ,
+ EQ_NCTN,
+ EQ_NFIX,
+ FROM_CODE_EVAL,
+ IDOF_DEF_CTN,
+ IDOF_EMP_IDOF,
+ IDOF_EQ_CST_START,
+ IDOF_EQ_NORM,
+ IDOF_EQ_NSTART,
+ IDOF_FIND,
+ IDOF_LEN,
+ IDOF_MAX,
+ IDOF_NCTN,
+ IDOF_NEG,
+ IDOF_NFIND,
+ IDOF_NORM_PREFIX,
+ IDOF_PULL_ENDPT,
+ IDOF_STRIP_CNST_ENDPTS,
+ IDOF_STRIP_SYM_LEN,
+ ITOS_EVAL,
+ RE_AND_EMPTY,
+ RE_ANDOR_FLATTEN,
+ RE_CHAR_IN_STR_STAR,
+ RE_CONCAT,
+ RE_CONCAT_FLATTEN,
+ RE_CONCAT_OPT,
+ RE_CONCAT_PURE_ALLCHAR,
+ RE_CONCAT_TO_CONTAINS,
+ RE_EMPTY_IN_STR_STAR,
+ RE_IN_DIST_CHAR_STAR,
+ RE_IN_SIGMA_STAR,
+ RE_LOOP,
+ RE_LOOP_STAR,
+ RE_OR_ALL,
+ RE_SIMPLE_CONSUME,
+ RE_STAR_EMPTY,
+ RE_STAR_EMPTY_STRING,
+ RE_STAR_NESTED_STAR,
+ RE_STAR_UNION,
+ REPL_CHAR_NCONTRIB_FIND,
+ REPL_DUAL_REPL_ITE,
+ REPL_REPL_SHORT_CIRCUIT,
+ REPL_REPL2_INV,
+ REPL_REPL2_INV_ID,
+ REPL_REPL3_INV,
+ REPL_REPL3_INV_ID,
+ REPL_SUBST_IDX,
+ REPLALL_CONST,
+ REPLALL_EMPTY_FIND,
+ RPL_CCTN,
+ RPL_CCTN_RPL,
+ RPL_CNTS_SUBSTS,
+ RPL_CONST_FIND,
+ RPL_CONST_NFIND,
+ RPL_EMP_CNTS_SUBSTS,
+ RPL_ID,
+ RPL_NCTN,
+ RPL_PULL_ENDPT,
+ RPL_REPLACE,
+ RPL_RPL_EMPTY,
+ RPL_RPL_LEN_ID,
+ RPL_X_Y_X_SIMP,
+ SPLIT_EQ,
+ SPLIT_EQ_STRIP_L,
+ SPLIT_EQ_STRIP_R,
+ SS_COMBINE,
+ SS_CONST_END_OOB,
+ SS_CONST_LEN_MAX_OOB,
+ SS_CONST_LEN_NON_POS,
+ SS_CONST_SS,
+ SS_CONST_START_MAX_OOB,
+ SS_CONST_START_NEG,
+ SS_CONST_START_OOB,
+ SS_EMPTYSTR,
+ SS_END_PT_NORM,
+ SS_GEQ_ZERO_START_ENTAILS_EMP_S,
+ SS_LEN_INCLUDE,
+ SS_LEN_NON_POS,
+ SS_LEN_ONE_Z_Z,
+ SS_NON_ZERO_LEN_ENTAILS_OOB,
+ SS_START_ENTAILS_ZERO_LEN,
+ SS_START_GEQ_LEN,
+ SS_START_NEG,
+ SS_STRIP_END_PT,
+ SS_STRIP_START_PT,
+ STOI_CONCAT_NONNUM,
+ STOI_EVAL,
+ STR_CONV_CONST,
+ STR_CONV_IDEM,
+ STR_CONV_ITOS,
+ STR_CONV_MINSCOPE_CONCAT,
+ STR_EMP_REPL_EMP,
+ STR_EMP_REPL_EMP_R,
+ STR_EMP_REPL_X_Y_X,
+ STR_EMP_SUBSTR_ELIM,
+ STR_EMP_SUBSTR_LEQ_LEN,
+ STR_EMP_SUBSTR_LEQ_Z,
+ STR_EQ_CONJ_LEN_ENTAIL,
+ STR_EQ_CONST_NHOMOG,
+ STR_EQ_HOMOG_CONST,
+ STR_EQ_REPL_EMP,
+ STR_EQ_REPL_NOT_CTN,
+ STR_EQ_REPL_TO_DIS,
+ STR_EQ_REPL_TO_EQ,
+ STR_EQ_UNIFY,
+ STR_LEQ_CPREFIX,
+ STR_LEQ_EMPTY,
+ STR_LEQ_EVAL,
+ STR_LEQ_ID,
+ STR_REV_CONST,
+ STR_REV_IDEM,
+ STR_REV_MINSCOPE_CONCAT,
+ SUBSTR_REPL_SWAP,
+ SUF_PREFIX_CONST,
+ SUF_PREFIX_CTN,
+ SUF_PREFIX_EMPTY,
+ SUF_PREFIX_EMPTY_CONST,
+ SUF_PREFIX_EQ,
+ SUF_PREFIX_TO_EQS,
+ TO_CODE_EVAL,
+ EQ_REFL,
+ EQ_CONST_FALSE,
+ EQ_SYM,
+ CONCAT_NORM,
+ IS_DIGIT_ELIM,
+ RE_CONCAT_EMPTY,
+ RE_CONSUME_CCONF,
+ RE_CONSUME_S,
+ RE_CONSUME_S_CCONF,
+ RE_CONSUME_S_FULL,
+ RE_IN_EMPTY,
+ RE_IN_SIGMA,
+ RE_IN_EVAL,
+ RE_IN_COMPLEMENT,
+ RE_IN_RANGE,
+ RE_IN_CSTRING,
+ RE_IN_ANDOR,
+ RE_REPEAT_ELIM,
+ SUF_PREFIX_ELIM,
+ STR_LT_ELIM,
+ RE_RANGE_SINGLE,
+ RE_OPT_ELIM,
+ RE_PLUS_ELIM,
+ RE_DIFF_ELIM,
+ LEN_EVAL,
+ LEN_CONCAT,
+ LEN_REPL_INV,
+ LEN_CONV_INV,
+ CHARAT_ELIM
+};
+
+/**
+ * Converts an rewrite to a string. Note: This function is also used in
+ * `safe_print()`. Changing this functions name or signature will result in
+ * `safe_print()` printing "<unsupported>" instead of the proper strings for
+ * the enum values.
+ *
+ * @param r The rewrite
+ * @return The name of the rewrite
+ */
+const char* toString(Rewrite r);
+
+/**
+ * Writes an rewrite name to a stream.
+ *
+ * @param out The stream to write to
+ * @param r The rewrite to write to the stream
+ * @return The stream
+ */
+std::ostream& operator<<(std::ostream& out, Rewrite r);
+
+} // namespace strings
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__STRINGS__REWRITES_H */
diff --git a/src/theory/strings/sequences_rewriter.cpp b/src/theory/strings/sequences_rewriter.cpp
index 200d7a734..be1e13459 100644
--- a/src/theory/strings/sequences_rewriter.cpp
+++ b/src/theory/strings/sequences_rewriter.cpp
@@ -310,11 +310,13 @@ Node SequencesRewriter::rewriteEquality(Node node)
Assert(node.getKind() == kind::EQUAL);
if (node[0] == node[1])
{
- return NodeManager::currentNM()->mkConst(true);
+ Node ret = NodeManager::currentNM()->mkConst(true);
+ return returnRewrite(node, ret, Rewrite::EQ_REFL);
}
else if (node[0].isConst() && node[1].isConst())
{
- return NodeManager::currentNM()->mkConst(false);
+ Node ret = NodeManager::currentNM()->mkConst(false);
+ return returnRewrite(node, ret, Rewrite::EQ_CONST_FALSE);
}
// ( ~contains( s, t ) V ~contains( t, s ) ) => ( s == t ---> false )
@@ -328,7 +330,7 @@ Node SequencesRewriter::rewriteEquality(Node node)
{
if (!ctn.getConst<bool>())
{
- return returnRewrite(node, ctn, "eq-nctn");
+ return returnRewrite(node, ctn, Rewrite::EQ_NCTN);
}
else
{
@@ -347,7 +349,7 @@ Node SequencesRewriter::rewriteEquality(Node node)
len_eq = Rewriter::rewrite(len_eq);
if (len_eq.isConst() && !len_eq.getConst<bool>())
{
- return returnRewrite(node, len_eq, "eq-len-deq");
+ return returnRewrite(node, len_eq, Rewrite::EQ_LEN_DEQ);
}
std::vector<Node> c[2];
@@ -375,7 +377,7 @@ Node SequencesRewriter::rewriteEquality(Node node)
if (!isSameFix)
{
Node ret = NodeManager::currentNM()->mkConst(false);
- return returnRewrite(node, ret, "eq-nfix");
+ return returnRewrite(node, ret, Rewrite::EQ_NFIX);
}
}
if (c[0][index1] != c[1][index2])
@@ -388,7 +390,8 @@ Node SequencesRewriter::rewriteEquality(Node node)
// standard ordering
if (node[0] > node[1])
{
- return NodeManager::currentNM()->mkNode(kind::EQUAL, node[1], node[0]);
+ Node ret = NodeManager::currentNM()->mkNode(kind::EQUAL, node[1], node[0]);
+ return returnRewrite(node, ret, Rewrite::EQ_SYM);
}
return node;
}
@@ -400,7 +403,7 @@ Node SequencesRewriter::rewriteEqualityExt(Node node)
{
return rewriteArithEqualityExt(node);
}
- if (node[0].getType().isString())
+ if (node[0].getType().isStringLike())
{
return rewriteStrEqualityExt(node);
}
@@ -409,7 +412,7 @@ Node SequencesRewriter::rewriteEqualityExt(Node node)
Node SequencesRewriter::rewriteStrEqualityExt(Node node)
{
- Assert(node.getKind() == EQUAL && node[0].getType().isString());
+ Assert(node.getKind() == EQUAL && node[0].getType().isStringLike());
TypeNode stype = node[0].getType();
NodeManager* nm = NodeManager::currentNM();
@@ -465,7 +468,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
Node s1 = utils::mkConcat(c[0], stype);
Node s2 = utils::mkConcat(c[1], stype);
new_ret = s1.eqNode(s2);
- node = returnRewrite(node, new_ret, "str-eq-unify");
+ node = returnRewrite(node, new_ret, Rewrite::STR_EQ_UNIFY);
}
// ------- homogeneous constants
@@ -476,13 +479,12 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
{
Assert(cn.isConst());
Assert(Word::getLength(cn) == 1);
- unsigned hchar = cn.getConst<String>().front();
// The operands of the concat on each side of the equality without
// constant strings
std::vector<Node> trimmed[2];
- // Counts the number of `hchar`s on each side
- size_t numHChars[2] = {0, 0};
+ // Counts the number of `cn`s on each side
+ size_t numCns[2] = {0, 0};
for (size_t j = 0; j < 2; j++)
{
// Sort the operands of the concats on both sides of the equality
@@ -493,21 +495,21 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
{
if (cc.isConst())
{
- // Count the number of `hchar`s in the string constant and make
- // sure that all chars are `hchar`s
- std::vector<unsigned> veccc = cc.getConst<String>().getVec();
- for (size_t k = 0, size = veccc.size(); k < size; k++)
+ // Count the number of `cn`s in the string constant and make
+ // sure that all chars are `cn`s
+ std::vector<Node> veccc = Word::getChars(cc);
+ for (const Node& cv : veccc)
{
- if (veccc[k] != hchar)
+ if (cv != cn)
{
// This conflict case should mostly should be taken care of by
// multiset reasoning in the strings rewriter, but we recognize
// this conflict just in case.
new_ret = nm->mkConst(false);
return returnRewrite(
- node, new_ret, "string-eq-const-conflict-non-homog");
+ node, new_ret, Rewrite::STR_EQ_CONST_NHOMOG);
}
- numHChars[j]++;
+ numCns[j]++;
}
}
else
@@ -517,18 +519,18 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
}
}
- // We have to remove the same number of `hchar`s from both sides, so the
- // side with less `hchar`s determines how many we can remove
- size_t trimmedConst = std::min(numHChars[0], numHChars[1]);
+ // We have to remove the same number of `cn`s from both sides, so the
+ // side with less `cn`s determines how many we can remove
+ size_t trimmedConst = std::min(numCns[0], numCns[1]);
for (size_t j = 0; j < 2; j++)
{
- size_t diff = numHChars[j] - trimmedConst;
+ size_t diff = numCns[j] - trimmedConst;
if (diff != 0)
{
- // Add a constant string to the side with more `hchar`s to restore
- // the difference in number of `hchar`s
- std::vector<unsigned> vec(diff, hchar);
- trimmed[j].push_back(nm->mkConst(String(vec)));
+ // Add a constant string to the side with more `cn`s to restore
+ // the difference in number of `cn`s
+ std::vector<Node> vec(diff, cn);
+ trimmed[j].push_back(Word::mkWord(vec));
}
}
@@ -540,7 +542,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
// "AA" = y ++ x ---> "AA" = x ++ y if x < y
// "AAA" = y ++ "A" ++ z ---> "AA" = y ++ z
new_ret = lhs.eqNode(ss);
- node = returnRewrite(node, new_ret, "str-eq-homog-const");
+ node = returnRewrite(node, new_ret, Rewrite::STR_EQ_HOMOG_CONST);
}
}
}
@@ -558,7 +560,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
if (ne[0] == ne[2])
{
Node ret = nm->mkNode(EQUAL, ne[0], empty);
- return returnRewrite(node, ret, "str-emp-repl-x-y-x");
+ return returnRewrite(node, ret, Rewrite::STR_EMP_REPL_X_Y_X);
}
// (= "" (str.replace x y "A")) ---> (and (= x "") (not (= y "")))
@@ -568,14 +570,14 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
nm->mkNode(AND,
nm->mkNode(EQUAL, ne[0], empty),
nm->mkNode(NOT, nm->mkNode(EQUAL, ne[1], empty)));
- return returnRewrite(node, ret, "str-emp-repl-emp");
+ return returnRewrite(node, ret, Rewrite::STR_EMP_REPL_EMP);
}
// (= "" (str.replace x "A" "")) ---> (str.prefix x "A")
if (checkEntailLengthOne(ne[1]) && ne[2] == empty)
{
Node ret = nm->mkNode(STRING_PREFIX, ne[0], ne[1]);
- return returnRewrite(node, ret, "str-emp-repl-emp");
+ return returnRewrite(node, ret, Rewrite::STR_EMP_REPL_EMP);
}
}
else if (ne.getKind() == STRING_SUBSTR)
@@ -588,20 +590,20 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
if (ne[1] == zero)
{
Node ret = nm->mkNode(EQUAL, ne[0], empty);
- return returnRewrite(node, ret, "str-emp-substr-leq-len");
+ return returnRewrite(node, ret, Rewrite::STR_EMP_SUBSTR_LEQ_LEN);
}
// (= "" (str.substr x n m)) ---> (<= (str.len x) n)
// if n >= 0 and m > 0
Node ret = nm->mkNode(LEQ, nm->mkNode(STRING_LENGTH, ne[0]), ne[1]);
- return returnRewrite(node, ret, "str-emp-substr-leq-len");
+ return returnRewrite(node, ret, Rewrite::STR_EMP_SUBSTR_LEQ_LEN);
}
// (= "" (str.substr "A" 0 z)) ---> (<= z 0)
if (checkEntailNonEmpty(ne[0]) && ne[1] == zero)
{
Node ret = nm->mkNode(LEQ, ne[2], zero);
- return returnRewrite(node, ret, "str-emp-substr-leq-z");
+ return returnRewrite(node, ret, Rewrite::STR_EMP_SUBSTR_LEQ_Z);
}
}
}
@@ -620,14 +622,14 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
{
Node ret = nm->mkNode(
EQUAL, empty, nm->mkNode(STRING_STRREPL, x, repl[2], repl[1]));
- return returnRewrite(node, ret, "str-eq-repl-emp");
+ return returnRewrite(node, ret, Rewrite::STR_EQ_REPL_EMP);
}
// (= x (str.replace y x y)) ---> (= x y)
if (repl[0] == repl[2] && x == repl[1])
{
Node ret = nm->mkNode(EQUAL, x, repl[0]);
- return returnRewrite(node, ret, "str-eq-repl-to-eq");
+ return returnRewrite(node, ret, Rewrite::STR_EQ_REPL_TO_EQ);
}
// (= x (str.replace x "A" "B")) ---> (not (str.contains x "A"))
@@ -637,7 +639,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
if (eq.isConst() && !eq.getConst<bool>())
{
Node ret = nm->mkNode(NOT, nm->mkNode(STRING_STRCTN, x, repl[1]));
- return returnRewrite(node, ret, "str-eq-repl-not-ctn");
+ return returnRewrite(node, ret, Rewrite::STR_EQ_REPL_NOT_CTN);
}
}
@@ -652,7 +654,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
Node ret = nm->mkNode(OR,
nm->mkNode(EQUAL, repl[0], repl[1]),
nm->mkNode(EQUAL, repl[0], repl[2]));
- return returnRewrite(node, ret, "str-eq-repl-to-dis");
+ return returnRewrite(node, ret, Rewrite::STR_EQ_REPL_TO_DIS);
}
}
}
@@ -673,7 +675,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
new_ret = inferEqsFromContains(node[i], node[1 - i]);
if (!new_ret.isNull())
{
- return returnRewrite(node, new_ret, "str-eq-conj-len-entail");
+ return returnRewrite(node, new_ret, Rewrite::STR_EQ_CONJ_LEN_ENTAIL);
}
}
}
@@ -715,7 +717,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
pfx0.eqNode(pfx1),
utils::mkConcat(sfxv0, stype)
.eqNode(utils::mkConcat(sfxv1, stype)));
- return returnRewrite(node, ret, "split-eq");
+ return returnRewrite(node, ret, Rewrite::SPLIT_EQ);
}
else if (checkEntailArith(lenPfx1, lenPfx0, true))
{
@@ -735,7 +737,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
pfx0.eqNode(utils::mkConcat(rpfxv1, stype)),
utils::mkConcat(sfxv0, stype)
.eqNode(utils::mkConcat(pfxv1, stype)));
- return returnRewrite(node, ret, "split-eq-strip-r");
+ return returnRewrite(node, ret, Rewrite::SPLIT_EQ_STRIP_R);
}
// If the prefix of the right-hand side is (strictly) longer than
@@ -762,7 +764,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
utils::mkConcat(rpfxv0, stype).eqNode(pfx1),
utils::mkConcat(pfxv0, stype)
.eqNode(utils::mkConcat(sfxv1, stype)));
- return returnRewrite(node, ret, "split-eq-strip-l");
+ return returnRewrite(node, ret, Rewrite::SPLIT_EQ_STRIP_L);
}
// If the prefix of the left-hand side is (strictly) longer than
@@ -790,6 +792,59 @@ Node SequencesRewriter::rewriteArithEqualityExt(Node node)
return node;
}
+Node SequencesRewriter::rewriteLength(Node node)
+{
+ Assert(node.getKind() == STRING_LENGTH);
+ NodeManager* nm = NodeManager::currentNM();
+ Kind nk0 = node[0].getKind();
+ if (node[0].isConst())
+ {
+ Node retNode = nm->mkConst(Rational(Word::getLength(node[0])));
+ return returnRewrite(node, retNode, Rewrite::LEN_EVAL);
+ }
+ else if (nk0 == kind::STRING_CONCAT)
+ {
+ Node tmpNode = node[0];
+ if (tmpNode.getKind() == kind::STRING_CONCAT)
+ {
+ std::vector<Node> node_vec;
+ for (unsigned int i = 0; i < tmpNode.getNumChildren(); ++i)
+ {
+ if (tmpNode[i].isConst())
+ {
+ node_vec.push_back(
+ nm->mkConst(Rational(Word::getLength(tmpNode[i]))));
+ }
+ else
+ {
+ node_vec.push_back(NodeManager::currentNM()->mkNode(
+ kind::STRING_LENGTH, tmpNode[i]));
+ }
+ }
+ Node retNode = NodeManager::currentNM()->mkNode(kind::PLUS, node_vec);
+ return returnRewrite(node, retNode, Rewrite::LEN_CONCAT);
+ }
+ }
+ else if (nk0 == STRING_STRREPL || nk0 == STRING_STRREPLALL)
+ {
+ Node len1 = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, node[0][1]));
+ Node len2 = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, node[0][2]));
+ if (len1 == len2)
+ {
+ // len( y ) == len( z ) => len( str.replace( x, y, z ) ) ---> len( x )
+ Node retNode = nm->mkNode(STRING_LENGTH, node[0][0]);
+ return returnRewrite(node, retNode, Rewrite::LEN_REPL_INV);
+ }
+ }
+ else if (nk0 == STRING_TOLOWER || nk0 == STRING_TOUPPER || nk0 == STRING_REV)
+ {
+ // len( f( x ) ) == len( x ) where f is tolower, toupper, or rev.
+ Node retNode = nm->mkNode(STRING_LENGTH, node[0][0]);
+ return returnRewrite(node, retNode, Rewrite::LEN_CONV_INV);
+ }
+ return node;
+}
+
// TODO (#1180) add rewrite
// str.++( str.substr( x, n1, n2 ), str.substr( x, n1+n2, n3 ) ) --->
// str.substr( x, n1, n2+n3 )
@@ -799,7 +854,6 @@ Node SequencesRewriter::rewriteConcat(Node node)
Trace("strings-rewrite-debug")
<< "Strings::rewriteConcat start " << node << std::endl;
NodeManager* nm = NodeManager::currentNM();
- Node retNode = node;
std::vector<Node> node_vec;
Node preNode = Node::null();
for (Node tmpNode : node)
@@ -890,10 +944,14 @@ Node SequencesRewriter::rewriteConcat(Node node)
std::sort(node_vec.begin() + lastIdx, node_vec.end());
TypeNode tn = node.getType();
- retNode = utils::mkConcat(node_vec, tn);
+ Node retNode = utils::mkConcat(node_vec, tn);
Trace("strings-rewrite-debug")
<< "Strings::rewriteConcat end " << retNode << std::endl;
- return retNode;
+ if (retNode != node)
+ {
+ return returnRewrite(node, retNode, Rewrite::CONCAT_NORM);
+ }
+ return node;
}
Node SequencesRewriter::rewriteConcatRegExp(TNode node)
@@ -940,7 +998,8 @@ Node SequencesRewriter::rewriteConcatRegExp(TNode node)
{
// re.++( ..., empty, ... ) ---> empty
std::vector<Node> nvec;
- return nm->mkNode(REGEXP_EMPTY, nvec);
+ Node ret = nm->mkNode(REGEXP_EMPTY, nvec);
+ return returnRewrite(node, ret, Rewrite::RE_CONCAT_EMPTY);
}
else
{
@@ -961,7 +1020,7 @@ Node SequencesRewriter::rewriteConcatRegExp(TNode node)
{
retNode = vec.size() == 1 ? vec[0] : nm->mkNode(REGEXP_CONCAT, vec);
}
- return returnRewrite(node, retNode, "re.concat-flatten");
+ return returnRewrite(node, retNode, Rewrite::RE_CONCAT_FLATTEN);
}
Trace("strings-rewrite-debug")
<< "Strings::rewriteConcatRegExp start " << node << std::endl;
@@ -1039,7 +1098,7 @@ Node SequencesRewriter::rewriteConcatRegExp(TNode node)
{
// handles all cases where consecutive re constants are combined or
// dropped as described in the loop above.
- return returnRewrite(node, retNode, "re.concat");
+ return returnRewrite(node, retNode, Rewrite::RE_CONCAT);
}
// flipping adjacent star arguments
@@ -1056,7 +1115,7 @@ Node SequencesRewriter::rewriteConcatRegExp(TNode node)
if (changed)
{
retNode = utils::mkConcat(cvec, rtype);
- return returnRewrite(node, retNode, "re.concat.opt");
+ return returnRewrite(node, retNode, Rewrite::RE_CONCAT_OPT);
}
return node;
}
@@ -1069,19 +1128,19 @@ Node SequencesRewriter::rewriteStarRegExp(TNode node)
if (node[0].getKind() == REGEXP_STAR)
{
// ((R)*)* ---> R*
- return returnRewrite(node, node[0], "re-star-nested-star");
+ return returnRewrite(node, node[0], Rewrite::RE_STAR_NESTED_STAR);
}
else if (node[0].getKind() == STRING_TO_REGEXP && node[0][0].isConst()
&& Word::isEmpty(node[0][0]))
{
// ("")* ---> ""
- return returnRewrite(node, node[0], "re-star-empty-string");
+ return returnRewrite(node, node[0], Rewrite::RE_STAR_EMPTY_STRING);
}
else if (node[0].getKind() == REGEXP_EMPTY)
{
// (empty)* ---> ""
retNode = nm->mkNode(STRING_TO_REGEXP, nm->mkConst(String("")));
- return returnRewrite(node, retNode, "re-star-empty");
+ return returnRewrite(node, retNode, Rewrite::RE_STAR_EMPTY);
}
else if (node[0].getKind() == REGEXP_UNION)
{
@@ -1110,7 +1169,7 @@ Node SequencesRewriter::rewriteStarRegExp(TNode node)
retNode = nm->mkNode(REGEXP_STAR, retNode);
// simplification of union beneath star based on loop above
// for example, ( "" | "a" )* ---> ("a")*
- return returnRewrite(node, retNode, "re-star-union");
+ return returnRewrite(node, retNode, Rewrite::RE_STAR_UNION);
}
}
}
@@ -1140,7 +1199,7 @@ Node SequencesRewriter::rewriteAndOrRegExp(TNode node)
{
if (nk == REGEXP_INTER)
{
- return returnRewrite(node, ni, "re.and-empty");
+ return returnRewrite(node, ni, Rewrite::RE_AND_EMPTY);
}
// otherwise, can ignore
}
@@ -1148,7 +1207,7 @@ Node SequencesRewriter::rewriteAndOrRegExp(TNode node)
{
if (nk == REGEXP_UNION)
{
- return returnRewrite(node, ni, "re.or-all");
+ return returnRewrite(node, ni, Rewrite::RE_OR_ALL);
}
// otherwise, can ignore
}
@@ -1178,7 +1237,7 @@ Node SequencesRewriter::rewriteAndOrRegExp(TNode node)
if (retNode != node)
{
// flattening and removing children, based on loop above
- return returnRewrite(node, retNode, "re.andor-flatten");
+ return returnRewrite(node, retNode, Rewrite::RE_ANDOR_FLATTEN);
}
return node;
}
@@ -1190,69 +1249,101 @@ Node SequencesRewriter::rewriteLoopRegExp(TNode node)
Node r = node[0];
if (r.getKind() == REGEXP_STAR)
{
- return returnRewrite(node, r, "re.loop-star");
+ return returnRewrite(node, r, Rewrite::RE_LOOP_STAR);
}
- TNode n1 = node[1];
NodeManager* nm = NodeManager::currentNM();
CVC4::Rational rMaxInt(String::maxSize());
- AlwaysAssert(n1.isConst()) << "re.loop contains non-constant integer (1).";
- AlwaysAssert(n1.getConst<Rational>().sgn() >= 0)
- << "Negative integer in string REGEXP_LOOP (1)";
- Assert(n1.getConst<Rational>() <= rMaxInt)
- << "Exceeded UINT32_MAX in string REGEXP_LOOP (1)";
- uint32_t l = n1.getConst<Rational>().getNumerator().toUnsignedInt();
+ uint32_t l = utils::getLoopMinOccurrences(node);
std::vector<Node> vec_nodes;
for (unsigned i = 0; i < l; i++)
{
vec_nodes.push_back(r);
}
- if (node.getNumChildren() == 3)
+ Node n =
+ vec_nodes.size() == 0
+ ? nm->mkNode(STRING_TO_REGEXP, nm->mkConst(String("")))
+ : vec_nodes.size() == 1 ? r : nm->mkNode(REGEXP_CONCAT, vec_nodes);
+ uint32_t u = utils::getLoopMaxOccurrences(node);
+ if (u < l)
{
- TNode n2 = Rewriter::rewrite(node[2]);
- Node n =
- vec_nodes.size() == 0
- ? nm->mkNode(STRING_TO_REGEXP, nm->mkConst(String("")))
- : vec_nodes.size() == 1 ? r : nm->mkNode(REGEXP_CONCAT, vec_nodes);
- AlwaysAssert(n2.isConst()) << "re.loop contains non-constant integer (2).";
- AlwaysAssert(n2.getConst<Rational>().sgn() >= 0)
- << "Negative integer in string REGEXP_LOOP (2)";
- Assert(n2.getConst<Rational>() <= rMaxInt)
- << "Exceeded UINT32_MAX in string REGEXP_LOOP (2)";
- uint32_t u = n2.getConst<Rational>().getNumerator().toUnsignedInt();
- if (u <= l)
- {
- retNode = n;
- }
- else
- {
- std::vector<Node> vec2;
- vec2.push_back(n);
- TypeNode rtype = nm->regExpType();
- for (unsigned j = l; j < u; j++)
- {
- vec_nodes.push_back(r);
- n = utils::mkConcat(vec_nodes, rtype);
- vec2.push_back(n);
- }
- retNode = nm->mkNode(REGEXP_UNION, vec2);
- }
+ std::vector<Node> nvec;
+ retNode = nm->mkNode(REGEXP_EMPTY, nvec);
+ }
+ else if (u == l)
+ {
+ retNode = n;
}
else
{
- Node rest = nm->mkNode(REGEXP_STAR, r);
- retNode = vec_nodes.size() == 0
- ? rest
- : vec_nodes.size() == 1
- ? nm->mkNode(REGEXP_CONCAT, r, rest)
- : nm->mkNode(REGEXP_CONCAT,
- nm->mkNode(REGEXP_CONCAT, vec_nodes),
- rest);
+ std::vector<Node> vec2;
+ vec2.push_back(n);
+ TypeNode rtype = nm->regExpType();
+ for (uint32_t j = l; j < u; j++)
+ {
+ vec_nodes.push_back(r);
+ n = utils::mkConcat(vec_nodes, rtype);
+ vec2.push_back(n);
+ }
+ retNode = nm->mkNode(REGEXP_UNION, vec2);
}
Trace("strings-lp") << "Strings::lp " << node << " => " << retNode
<< std::endl;
if (retNode != node)
{
- return returnRewrite(node, retNode, "re.loop");
+ return returnRewrite(node, retNode, Rewrite::RE_LOOP);
+ }
+ return node;
+}
+
+Node SequencesRewriter::rewriteRepeatRegExp(TNode node)
+{
+ Assert(node.getKind() == REGEXP_REPEAT);
+ NodeManager* nm = NodeManager::currentNM();
+ // ((_ re.^ n) R) --> ((_ re.loop n n) R)
+ unsigned r = utils::getRepeatAmount(node);
+ Node lop = nm->mkConst(RegExpLoop(r, r));
+ Node retNode = nm->mkNode(REGEXP_LOOP, lop, node[0]);
+ return returnRewrite(node, retNode, Rewrite::RE_REPEAT_ELIM);
+}
+
+Node SequencesRewriter::rewriteOptionRegExp(TNode node)
+{
+ Assert(node.getKind() == REGEXP_OPT);
+ NodeManager* nm = NodeManager::currentNM();
+ Node retNode =
+ nm->mkNode(REGEXP_UNION,
+ nm->mkNode(STRING_TO_REGEXP, nm->mkConst(String(""))),
+ node[0]);
+ return returnRewrite(node, retNode, Rewrite::RE_OPT_ELIM);
+}
+
+Node SequencesRewriter::rewritePlusRegExp(TNode node)
+{
+ Assert(node.getKind() == REGEXP_PLUS);
+ NodeManager* nm = NodeManager::currentNM();
+ Node retNode =
+ nm->mkNode(REGEXP_CONCAT, node[0], nm->mkNode(REGEXP_STAR, node[0]));
+ return returnRewrite(node, retNode, Rewrite::RE_PLUS_ELIM);
+}
+
+Node SequencesRewriter::rewriteDifferenceRegExp(TNode node)
+{
+ Assert(node.getKind() == REGEXP_DIFF);
+ NodeManager* nm = NodeManager::currentNM();
+ Node retNode =
+ nm->mkNode(REGEXP_INTER, node[0], nm->mkNode(REGEXP_COMPLEMENT, node[1]));
+ return returnRewrite(node, retNode, Rewrite::RE_DIFF_ELIM);
+}
+
+Node SequencesRewriter::rewriteRangeRegExp(TNode node)
+{
+ Assert(node.getKind() == REGEXP_RANGE);
+ if (node[0] == node[1])
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ Node retNode = nm->mkNode(STRING_TO_REGEXP, node[0]);
+ // re.range( "A", "A" ) ---> str.to_re( "A" )
+ return returnRewrite(node, retNode, Rewrite::RE_RANGE_SINGLE);
}
return node;
}
@@ -1421,11 +1512,8 @@ bool SequencesRewriter::testConstStringInRegExp(CVC4::String& s,
if (s.size() == index_start + 1)
{
unsigned a = r[0].getConst<String>().front();
- a = String::convertUnsignedIntToCode(a);
unsigned b = r[1].getConst<String>().front();
- b = String::convertUnsignedIntToCode(b);
unsigned c = s.back();
- c = String::convertUnsignedIntToCode(c);
return (a <= c && c <= b);
}
else
@@ -1527,7 +1615,6 @@ bool SequencesRewriter::testConstStringInRegExp(CVC4::String& s,
Node SequencesRewriter::rewriteMembership(TNode node)
{
NodeManager* nm = NodeManager::currentNM();
- Node retNode = node;
Node x = node[0];
Node r = node[1];
@@ -1536,19 +1623,22 @@ Node SequencesRewriter::rewriteMembership(TNode node)
if(r.getKind() == kind::REGEXP_EMPTY)
{
- retNode = NodeManager::currentNM()->mkConst( false );
+ Node retNode = NodeManager::currentNM()->mkConst(false);
+ return returnRewrite(node, retNode, Rewrite::RE_IN_EMPTY);
}
else if (x.isConst() && isConstRegExp(r))
{
// test whether x in node[1]
CVC4::String s = x.getConst<String>();
- retNode =
+ Node retNode =
NodeManager::currentNM()->mkConst(testConstStringInRegExp(s, 0, r));
+ return returnRewrite(node, retNode, Rewrite::RE_IN_EVAL);
}
else if (r.getKind() == kind::REGEXP_SIGMA)
{
Node one = nm->mkConst(Rational(1));
- retNode = one.eqNode(nm->mkNode(STRING_LENGTH, x));
+ Node retNode = one.eqNode(nm->mkNode(STRING_LENGTH, x));
+ return returnRewrite(node, retNode, Rewrite::RE_IN_SIGMA);
}
else if (r.getKind() == kind::REGEXP_STAR)
{
@@ -1557,17 +1647,17 @@ Node SequencesRewriter::rewriteMembership(TNode node)
String s = x.getConst<String>();
if (s.size() == 0)
{
- retNode = nm->mkConst(true);
+ Node retNode = nm->mkConst(true);
// e.g. (str.in.re "" (re.* (str.to.re x))) ----> true
- return returnRewrite(node, retNode, "re-empty-in-str-star");
+ return returnRewrite(node, retNode, Rewrite::RE_EMPTY_IN_STR_STAR);
}
else if (s.size() == 1)
{
if (r[0].getKind() == STRING_TO_REGEXP)
{
- retNode = r[0][0].eqNode(x);
+ Node retNode = r[0][0].eqNode(x);
// e.g. (str.in.re "A" (re.* (str.to.re x))) ----> "A" = x
- return returnRewrite(node, retNode, "re-char-in-str-star");
+ return returnRewrite(node, retNode, Rewrite::RE_CHAR_IN_STR_STAR);
}
}
}
@@ -1588,14 +1678,14 @@ Node SequencesRewriter::rewriteMembership(TNode node)
nb << nm->mkNode(STRING_IN_REGEXP, xc, r);
}
return returnRewrite(
- node, nb.constructNode(), "re-in-dist-char-star");
+ node, nb.constructNode(), Rewrite::RE_IN_DIST_CHAR_STAR);
}
}
}
if (r[0].getKind() == kind::REGEXP_SIGMA)
{
- retNode = NodeManager::currentNM()->mkConst(true);
- return returnRewrite(node, retNode, "re-in-sigma-star");
+ Node retNode = NodeManager::currentNM()->mkConst(true);
+ return returnRewrite(node, retNode, Rewrite::RE_IN_SIGMA_STAR);
}
}
else if (r.getKind() == kind::REGEXP_CONCAT)
@@ -1644,15 +1734,15 @@ Node SequencesRewriter::rewriteMembership(TNode node)
// x in re.++(_*, _, _) ---> str.len(x) >= 2
Node num = nm->mkConst(Rational(allSigmaMinSize));
Node lenx = nm->mkNode(STRING_LENGTH, x);
- retNode = nm->mkNode(allSigmaStrict ? EQUAL : GEQ, lenx, num);
- return returnRewrite(node, retNode, "re-concat-pure-allchar");
+ Node retNode = nm->mkNode(allSigmaStrict ? EQUAL : GEQ, lenx, num);
+ return returnRewrite(node, retNode, Rewrite::RE_CONCAT_PURE_ALLCHAR);
}
else if (allSigmaMinSize == 0 && nchildren >= 3 && constIdx != 0
&& constIdx != nchildren - 1)
{
// x in re.++(_*, "abc", _*) ---> str.contains(x, "abc")
- retNode = nm->mkNode(STRING_STRCTN, x, constStr);
- return returnRewrite(node, retNode, "re-concat-to-contains");
+ Node retNode = nm->mkNode(STRING_STRCTN, x, constStr);
+ return returnRewrite(node, retNode, Rewrite::RE_CONCAT_TO_CONTAINS);
}
}
}
@@ -1665,132 +1755,125 @@ Node SequencesRewriter::rewriteMembership(TNode node)
mvec.push_back(
NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, r[i]));
}
- retNode = NodeManager::currentNM()->mkNode(
+ Node retNode = NodeManager::currentNM()->mkNode(
r.getKind() == kind::REGEXP_INTER ? kind::AND : kind::OR, mvec);
+ return returnRewrite(node, retNode, Rewrite::RE_IN_ANDOR);
}
else if (r.getKind() == kind::STRING_TO_REGEXP)
{
- retNode = x.eqNode(r[0]);
+ Node retNode = x.eqNode(r[0]);
+ return returnRewrite(node, retNode, Rewrite::RE_IN_CSTRING);
}
else if (r.getKind() == REGEXP_RANGE)
{
// x in re.range( char_i, char_j ) ---> i <= str.code(x) <= j
Node xcode = nm->mkNode(STRING_TO_CODE, x);
- retNode =
+ Node retNode =
nm->mkNode(AND,
nm->mkNode(LEQ, nm->mkNode(STRING_TO_CODE, r[0]), xcode),
nm->mkNode(LEQ, xcode, nm->mkNode(STRING_TO_CODE, r[1])));
+ return returnRewrite(node, retNode, Rewrite::RE_IN_RANGE);
}
else if (r.getKind() == REGEXP_COMPLEMENT)
{
- retNode = nm->mkNode(STRING_IN_REGEXP, x, r[0]).negate();
- }
- else if (x != node[0] || r != node[1])
- {
- retNode = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, r);
+ Node retNode = nm->mkNode(STRING_IN_REGEXP, x, r[0]).negate();
+ return returnRewrite(node, retNode, Rewrite::RE_IN_COMPLEMENT);
}
// do simple consumes
- if (retNode == node)
+ Node retNode = node;
+ if (r.getKind() == kind::REGEXP_STAR)
{
- if (r.getKind() == kind::REGEXP_STAR)
+ for (unsigned dir = 0; dir <= 1; dir++)
{
- for (unsigned dir = 0; dir <= 1; dir++)
+ std::vector<Node> mchildren;
+ utils::getConcat(x, mchildren);
+ bool success = true;
+ while (success)
{
- std::vector<Node> mchildren;
- utils::getConcat(x, mchildren);
- bool success = true;
- while (success)
+ success = false;
+ std::vector<Node> children;
+ utils::getConcat(r[0], children);
+ Node scn = simpleRegexpConsume(mchildren, children, dir);
+ if (!scn.isNull())
{
- success = false;
- std::vector<Node> children;
- utils::getConcat(r[0], children);
- Node scn = simpleRegexpConsume(mchildren, children, dir);
- if (!scn.isNull())
+ Trace("regexp-ext-rewrite")
+ << "Regexp star : const conflict : " << node << std::endl;
+ return returnRewrite(node, scn, Rewrite::RE_CONSUME_S_CCONF);
+ }
+ else if (children.empty())
+ {
+ // fully consumed one copy of the STAR
+ if (mchildren.empty())
{
Trace("regexp-ext-rewrite")
- << "Regexp star : const conflict : " << node << std::endl;
- return scn;
+ << "Regexp star : full consume : " << node << std::endl;
+ Node ret = NodeManager::currentNM()->mkConst(true);
+ return returnRewrite(node, ret, Rewrite::RE_CONSUME_S_FULL);
}
- else if (children.empty())
+ else
{
- // fully consumed one copy of the STAR
- if (mchildren.empty())
- {
- Trace("regexp-ext-rewrite")
- << "Regexp star : full consume : " << node << std::endl;
- return NodeManager::currentNM()->mkConst(true);
- }
- else
- {
- retNode = nm->mkNode(STRING_IN_REGEXP,
- utils::mkConcat(mchildren, stype),
- r);
- success = true;
- }
+ retNode = nm->mkNode(
+ STRING_IN_REGEXP, utils::mkConcat(mchildren, stype), r);
+ success = true;
}
}
- if (retNode != node)
- {
- Trace("regexp-ext-rewrite") << "Regexp star : rewrite " << node
- << " -> " << retNode << std::endl;
- break;
- }
+ }
+ if (retNode != node)
+ {
+ Trace("regexp-ext-rewrite") << "Regexp star : rewrite " << node
+ << " -> " << retNode << std::endl;
+ return returnRewrite(node, retNode, Rewrite::RE_CONSUME_S);
}
}
- else
- {
- std::vector<Node> children;
- utils::getConcat(r, children);
- std::vector<Node> mchildren;
- utils::getConcat(x, mchildren);
- unsigned prevSize = children.size() + mchildren.size();
- Node scn = simpleRegexpConsume(mchildren, children);
- if (!scn.isNull())
+ }
+ else
+ {
+ std::vector<Node> children;
+ utils::getConcat(r, children);
+ std::vector<Node> mchildren;
+ utils::getConcat(x, mchildren);
+ unsigned prevSize = children.size() + mchildren.size();
+ Node scn = simpleRegexpConsume(mchildren, children);
+ if (!scn.isNull())
+ {
+ Trace("regexp-ext-rewrite")
+ << "Regexp : const conflict : " << node << std::endl;
+ return returnRewrite(node, scn, Rewrite::RE_CONSUME_CCONF);
+ }
+ else if ((children.size() + mchildren.size()) != prevSize)
+ {
+ // Given a membership (str.++ x1 ... xn) in (re.++ r1 ... rm),
+ // above, we strip components to construct an equivalent membership:
+ // (str.++ xi .. xj) in (re.++ rk ... rl).
+ Node xn = utils::mkConcat(mchildren, stype);
+ Node emptyStr = nm->mkConst(String(""));
+ if (children.empty())
{
- Trace("regexp-ext-rewrite")
- << "Regexp : const conflict : " << node << std::endl;
- return scn;
+ // If we stripped all components on the right, then the left is
+ // equal to the empty string.
+ // e.g. (str.++ "a" x) in (re.++ (str.to.re "a")) ---> (= x "")
+ retNode = xn.eqNode(emptyStr);
}
else
{
- if ((children.size() + mchildren.size()) != prevSize)
- {
- // Given a membership (str.++ x1 ... xn) in (re.++ r1 ... rm),
- // above, we strip components to construct an equivalent membership:
- // (str.++ xi .. xj) in (re.++ rk ... rl).
- Node xn = utils::mkConcat(mchildren, stype);
- Node emptyStr = nm->mkConst(String(""));
- if (children.empty())
- {
- // If we stripped all components on the right, then the left is
- // equal to the empty string.
- // e.g. (str.++ "a" x) in (re.++ (str.to.re "a")) ---> (= x "")
- retNode = xn.eqNode(emptyStr);
- }
- else
- {
- // otherwise, construct the updated regular expression
- retNode = nm->mkNode(
- STRING_IN_REGEXP, xn, utils::mkConcat(children, rtype));
- }
- Trace("regexp-ext-rewrite") << "Regexp : rewrite : " << node << " -> "
- << retNode << std::endl;
- return returnRewrite(node, retNode, "re-simple-consume");
- }
+ // otherwise, construct the updated regular expression
+ retNode =
+ nm->mkNode(STRING_IN_REGEXP, xn, utils::mkConcat(children, rtype));
}
+ Trace("regexp-ext-rewrite")
+ << "Regexp : rewrite : " << node << " -> " << retNode << std::endl;
+ return returnRewrite(node, retNode, Rewrite::RE_SIMPLE_CONSUME);
}
}
- return retNode;
+ return node;
}
RewriteResponse SequencesRewriter::postRewrite(TNode node)
{
Trace("strings-postrewrite")
<< "Strings::postRewrite start " << node << std::endl;
- NodeManager* nm = NodeManager::currentNM();
Node retNode = node;
- Node orig = retNode;
Kind nk = node.getKind();
if (nk == kind::STRING_CONCAT)
{
@@ -1802,59 +1885,11 @@ RewriteResponse SequencesRewriter::postRewrite(TNode node)
}
else if (nk == kind::STRING_LENGTH)
{
- Kind nk0 = node[0].getKind();
- if (node[0].isConst())
- {
- retNode = nm->mkConst(Rational(Word::getLength(node[0])));
- }
- else if (nk0 == kind::STRING_CONCAT)
- {
- Node tmpNode = node[0];
- if (tmpNode.isConst())
- {
- retNode = nm->mkConst(Rational(Word::getLength(tmpNode)));
- }
- else if (tmpNode.getKind() == kind::STRING_CONCAT)
- {
- std::vector<Node> node_vec;
- for (unsigned int i = 0; i < tmpNode.getNumChildren(); ++i)
- {
- if (tmpNode[i].isConst())
- {
- node_vec.push_back(
- nm->mkConst(Rational(Word::getLength(tmpNode[i]))));
- }
- else
- {
- node_vec.push_back(NodeManager::currentNM()->mkNode(
- kind::STRING_LENGTH, tmpNode[i]));
- }
- }
- retNode = NodeManager::currentNM()->mkNode(kind::PLUS, node_vec);
- }
- }
- else if (nk0 == STRING_STRREPL || nk0 == STRING_STRREPLALL)
- {
- Node len1 = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, node[0][1]));
- Node len2 = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, node[0][2]));
- if (len1 == len2)
- {
- // len( y ) == len( z ) => len( str.replace( x, y, z ) ) ---> len( x )
- retNode = nm->mkNode(STRING_LENGTH, node[0][0]);
- }
- }
- else if (nk0 == STRING_TOLOWER || nk0 == STRING_TOUPPER
- || nk0 == STRING_REV)
- {
- // len( f( x ) ) == len( x ) where f is tolower, toupper, or rev.
- retNode = nm->mkNode(STRING_LENGTH, node[0][0]);
- }
+ retNode = rewriteLength(node);
}
else if (nk == kind::STRING_CHARAT)
{
- Node one = NodeManager::currentNM()->mkConst(Rational(1));
- retNode = NodeManager::currentNM()->mkNode(
- kind::STRING_SUBSTR, node[0], node[1], one);
+ retNode = rewriteCharAt(node);
}
else if (nk == kind::STRING_SUBSTR)
{
@@ -1866,10 +1901,7 @@ RewriteResponse SequencesRewriter::postRewrite(TNode node)
}
else if (nk == kind::STRING_LT)
{
- // eliminate s < t ---> s != t AND s <= t
- retNode = nm->mkNode(AND,
- node[0].eqNode(node[1]).negate(),
- nm->mkNode(STRING_LEQ, node[0], node[1]));
+ retNode = StringsRewriter::rewriteStringLt(node);
}
else if (nk == kind::STRING_LEQ)
{
@@ -1901,11 +1933,7 @@ RewriteResponse SequencesRewriter::postRewrite(TNode node)
}
else if (nk == STRING_IS_DIGIT)
{
- // eliminate str.is_digit(s) ----> 48 <= str.to_code(s) <= 57
- Node t = nm->mkNode(STRING_TO_CODE, node[0]);
- retNode = nm->mkNode(AND,
- nm->mkNode(LEQ, nm->mkConst(Rational(48)), t),
- nm->mkNode(LEQ, t, nm->mkConst(Rational(57))));
+ retNode = StringsRewriter::rewriteStringIsDigit(node);
}
else if (nk == kind::STRING_ITOS)
{
@@ -1937,8 +1965,7 @@ RewriteResponse SequencesRewriter::postRewrite(TNode node)
}
else if (nk == REGEXP_DIFF)
{
- retNode = nm->mkNode(
- REGEXP_INTER, node[0], nm->mkNode(REGEXP_COMPLEMENT, node[1]));
+ retNode = rewriteDifferenceRegExp(node);
}
else if (nk == REGEXP_STAR)
{
@@ -1946,36 +1973,34 @@ RewriteResponse SequencesRewriter::postRewrite(TNode node)
}
else if (nk == REGEXP_PLUS)
{
- retNode =
- nm->mkNode(REGEXP_CONCAT, node[0], nm->mkNode(REGEXP_STAR, node[0]));
+ retNode = rewritePlusRegExp(node);
}
else if (nk == REGEXP_OPT)
{
- retNode = nm->mkNode(REGEXP_UNION,
- nm->mkNode(STRING_TO_REGEXP, nm->mkConst(String(""))),
- node[0]);
+ retNode = rewriteOptionRegExp(node);
}
else if (nk == REGEXP_RANGE)
{
- if (node[0] == node[1])
- {
- retNode = nm->mkNode(STRING_TO_REGEXP, node[0]);
- }
+ retNode = rewriteRangeRegExp(node);
}
else if (nk == REGEXP_LOOP)
{
retNode = rewriteLoopRegExp(node);
}
+ else if (nk == REGEXP_REPEAT)
+ {
+ retNode = rewriteRepeatRegExp(node);
+ }
Trace("strings-postrewrite")
<< "Strings::postRewrite returning " << retNode << std::endl;
- if (orig != retNode)
+ if (node != retNode)
{
Trace("strings-rewrite-debug")
- << "Strings: post-rewrite " << orig << " to " << retNode << std::endl;
+ << "Strings: post-rewrite " << node << " to " << retNode << std::endl;
+ return RewriteResponse(REWRITE_AGAIN_FULL, retNode);
}
- return RewriteResponse(orig == retNode ? REWRITE_DONE : REWRITE_AGAIN_FULL,
- retNode);
+ return RewriteResponse(REWRITE_DONE, retNode);
}
bool SequencesRewriter::hasEpsilonNode(TNode node)
@@ -1996,6 +2021,15 @@ RewriteResponse SequencesRewriter::preRewrite(TNode node)
return RewriteResponse(REWRITE_DONE, node);
}
+Node SequencesRewriter::rewriteCharAt(Node node)
+{
+ Assert(node.getKind() == STRING_CHARAT);
+ NodeManager* nm = NodeManager::currentNM();
+ Node one = nm->mkConst(Rational(1));
+ Node retNode = nm->mkNode(STRING_SUBSTR, node[0], node[1], one);
+ return returnRewrite(node, retNode, Rewrite::CHARAT_ELIM);
+}
+
Node SequencesRewriter::rewriteSubstr(Node node)
{
Assert(node.getKind() == kind::STRING_SUBSTR);
@@ -2006,7 +2040,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
if (Word::isEmpty(node[0]))
{
Node ret = node[0];
- return returnRewrite(node, ret, "ss-emptystr");
+ return returnRewrite(node, ret, Rewrite::SS_EMPTYSTR);
}
// rewriting for constant arguments
if (node[1].isConst() && node[2].isConst())
@@ -2019,13 +2053,13 @@ Node SequencesRewriter::rewriteSubstr(Node node)
// start beyond the maximum size of strings
// thus, it must be beyond the end point of this string
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-const-start-max-oob");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_START_MAX_OOB);
}
else if (node[1].getConst<Rational>().sgn() < 0)
{
// start before the beginning of the string
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-const-start-neg");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_START_NEG);
}
else
{
@@ -2034,7 +2068,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
{
// start beyond the end of the string
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-const-start-oob");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_START_OOB);
}
}
if (node[2].getConst<Rational>() > rMaxInt)
@@ -2042,12 +2076,12 @@ Node SequencesRewriter::rewriteSubstr(Node node)
// take up to the end of the string
size_t lenS = Word::getLength(s);
Node ret = Word::suffix(s, lenS - start);
- return returnRewrite(node, ret, "ss-const-len-max-oob");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_LEN_MAX_OOB);
}
else if (node[2].getConst<Rational>().sgn() <= 0)
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-const-len-non-pos");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_LEN_NON_POS);
}
else
{
@@ -2058,13 +2092,13 @@ Node SequencesRewriter::rewriteSubstr(Node node)
// take up to the end of the string
size_t lenS = Word::getLength(s);
Node ret = Word::suffix(s, lenS - start);
- return returnRewrite(node, ret, "ss-const-end-oob");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_END_OOB);
}
else
{
// compute the substr using the constant string
Node ret = Word::substr(s, start, len);
- return returnRewrite(node, ret, "ss-const-ss");
+ return returnRewrite(node, ret, Rewrite::SS_CONST_SS);
}
}
}
@@ -2075,12 +2109,12 @@ Node SequencesRewriter::rewriteSubstr(Node node)
if (checkEntailArith(zero, node[1], true))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-start-neg");
+ return returnRewrite(node, ret, Rewrite::SS_START_NEG);
}
else if (checkEntailArith(zero, node[2]))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-len-non-pos");
+ return returnRewrite(node, ret, Rewrite::SS_LEN_NON_POS);
}
if (node[0].getKind() == STRING_SUBSTR)
@@ -2106,7 +2140,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
if (checkEntailArith(node[1], node[0][2]))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-start-geq-len");
+ return returnRewrite(node, ret, Rewrite::SS_START_GEQ_LEN);
}
}
else if (node[0].getKind() == STRING_STRREPL)
@@ -2124,7 +2158,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
nm->mkNode(kind::STRING_SUBSTR, node[0][0], node[1], node[2]),
node[0][1],
node[0][2]);
- return returnRewrite(node, ret, "substr-repl-swap");
+ return returnRewrite(node, ret, Rewrite::SUBSTR_REPL_SWAP);
}
}
}
@@ -2146,7 +2180,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
kind::STRING_SUBSTR, utils::mkConcat(n1, stype), node[1], curr));
}
Node ret = utils::mkConcat(childrenr, stype);
- return returnRewrite(node, ret, "ss-len-include");
+ return returnRewrite(node, ret, Rewrite::SS_LEN_INCLUDE);
}
}
@@ -2174,7 +2208,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
{
// end point beyond end point of string, map to tot_len
Node ret = nm->mkNode(kind::STRING_SUBSTR, node[0], node[1], tot_len);
- return returnRewrite(node, ret, "ss-end-pt-norm");
+ return returnRewrite(node, ret, Rewrite::SS_END_PT_NORM);
}
else
{
@@ -2189,7 +2223,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
if (checkEntailArithWithAssumption(n1_lt_tot_len, zero, node[2], false))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-start-entails-zero-len");
+ return returnRewrite(node, ret, Rewrite::SS_START_ENTAILS_ZERO_LEN);
}
// (str.substr s x y) --> "" if 0 < y |= x >= str.len(s)
@@ -2198,7 +2232,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
if (checkEntailArithWithAssumption(non_zero_len, node[1], tot_len, false))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-non-zero-len-entails-oob");
+ return returnRewrite(node, ret, Rewrite::SS_NON_ZERO_LEN_ENTAILS_OOB);
}
// (str.substr s x y) --> "" if x >= 0 |= 0 >= str.len(s)
@@ -2207,14 +2241,15 @@ Node SequencesRewriter::rewriteSubstr(Node node)
if (checkEntailArithWithAssumption(geq_zero_start, zero, tot_len, false))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-geq-zero-start-entails-emp-s");
+ return returnRewrite(
+ node, ret, Rewrite::SS_GEQ_ZERO_START_ENTAILS_EMP_S);
}
// (str.substr s x x) ---> "" if (str.len s) <= 1
if (node[1] == node[2] && checkEntailLengthOne(node[0]))
{
Node ret = Word::mkEmptyWord(node.getType());
- return returnRewrite(node, ret, "ss-len-one-z-z");
+ return returnRewrite(node, ret, Rewrite::SS_LEN_ONE_Z_Z);
}
}
if (!curr.isNull())
@@ -2228,7 +2263,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
{
Node ret = nm->mkNode(
kind::STRING_SUBSTR, utils::mkConcat(n1, stype), curr, node[2]);
- return returnRewrite(node, ret, "ss-strip-start-pt");
+ return returnRewrite(node, ret, Rewrite::SS_STRIP_START_PT);
}
else
{
@@ -2236,7 +2271,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
utils::mkConcat(n1, stype),
node[1],
node[2]);
- return returnRewrite(node, ret, "ss-strip-end-pt");
+ return returnRewrite(node, ret, Rewrite::SS_STRIP_END_PT);
}
}
}
@@ -2276,7 +2311,7 @@ Node SequencesRewriter::rewriteSubstr(Node node)
Node new_start = nm->mkNode(kind::PLUS, start_inner, start_outer);
Node ret =
nm->mkNode(kind::STRING_SUBSTR, node[0][0], new_start, new_len);
- return returnRewrite(node, ret, "ss-combine");
+ return returnRewrite(node, ret, Rewrite::SS_COMBINE);
}
}
}
@@ -2292,15 +2327,14 @@ Node SequencesRewriter::rewriteContains(Node node)
if (node[0] == node[1])
{
Node ret = NodeManager::currentNM()->mkConst(true);
- return returnRewrite(node, ret, "ctn-eq");
+ return returnRewrite(node, ret, Rewrite::CTN_EQ);
}
if (node[0].isConst())
{
- CVC4::String s = node[0].getConst<String>();
if (node[1].isConst())
{
Node ret = nm->mkConst(Word::find(node[0], node[1]) != std::string::npos);
- return returnRewrite(node, ret, "ctn-const");
+ return returnRewrite(node, ret, Rewrite::CTN_CONST);
}
else
{
@@ -2315,26 +2349,25 @@ Node SequencesRewriter::rewriteContains(Node node)
// uses this function, hence we want to conclude false if possible.
// len(x)>0 => contains( "", x ) ---> false
Node ret = NodeManager::currentNM()->mkConst(false);
- return returnRewrite(node, ret, "ctn-lhs-emptystr");
+ return returnRewrite(node, ret, Rewrite::CTN_LHS_EMPTYSTR);
}
}
else if (checkEntailLengthOne(t))
{
- const std::vector<unsigned>& vec = s.getVec();
-
+ std::vector<Node> vec = Word::getChars(node[0]);
+ Node emp = Word::mkEmptyWord(t.getType());
NodeBuilder<> nb(OR);
- nb << nm->mkConst(String("")).eqNode(t);
- for (unsigned c : vec)
+ nb << emp.eqNode(t);
+ for (const Node& c : vec)
{
- std::vector<unsigned> sv = {c};
- nb << nm->mkConst(String(sv)).eqNode(t);
+ nb << c.eqNode(t);
}
// str.contains("ABCabc", t) --->
// t = "" v t = "A" v t = "B" v t = "C" v t = "a" v t = "b" v t = "c"
// if len(t) <= 1
Node ret = nb;
- return returnRewrite(node, ret, "ctn-split");
+ return returnRewrite(node, ret, Rewrite::CTN_SPLIT);
}
else if (node[1].getKind() == kind::STRING_CONCAT)
{
@@ -2342,7 +2375,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (!canConstantContainConcat(node[0], node[1], firstc, lastc))
{
Node ret = NodeManager::currentNM()->mkConst(false);
- return returnRewrite(node, ret, "ctn-nconst-ctn-concat");
+ return returnRewrite(node, ret, Rewrite::CTN_NCONST_CTN_CONCAT);
}
}
}
@@ -2354,7 +2387,7 @@ Node SequencesRewriter::rewriteContains(Node node)
{
// contains( x, "" ) ---> true
Node ret = NodeManager::currentNM()->mkConst(true);
- return returnRewrite(node, ret, "ctn-rhs-emptystr");
+ return returnRewrite(node, ret, Rewrite::CTN_RHS_EMPTYSTR);
}
else if (len == 1)
{
@@ -2373,7 +2406,7 @@ Node SequencesRewriter::rewriteContains(Node node)
Node ret = nb.constructNode();
// str.contains( x ++ y, "A" ) --->
// str.contains( x, "A" ) OR str.contains( y, "A" )
- return returnRewrite(node, ret, "ctn-concat-char");
+ return returnRewrite(node, ret, Rewrite::CTN_CONCAT_CHAR);
}
else if (node[0].getKind() == STRING_STRREPL)
{
@@ -2390,7 +2423,7 @@ Node SequencesRewriter::rewriteContains(Node node)
// str.contains( str.replace( x, y, z ), "A" ) --->
// str.contains( x, "A" ) OR
// ( str.contains( x, y ) AND str.contains( z, "A" ) )
- return returnRewrite(node, ret, "ctn-repl-char");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_CHAR);
}
}
}
@@ -2406,7 +2439,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (componentContains(nc1, nc2, nc1rb, nc1re) != -1)
{
Node ret = NodeManager::currentNM()->mkConst(true);
- return returnRewrite(node, ret, "ctn-component");
+ return returnRewrite(node, ret, Rewrite::CTN_COMPONENT);
}
TypeNode stype = node[0].getType();
@@ -2417,7 +2450,7 @@ Node SequencesRewriter::rewriteContains(Node node)
{
Node ret = NodeManager::currentNM()->mkNode(
kind::STRING_STRCTN, utils::mkConcat(nc1, stype), node[1]);
- return returnRewrite(node, ret, "ctn-strip-endpt");
+ return returnRewrite(node, ret, Rewrite::CTN_STRIP_ENDPT);
}
for (const Node& n : nc2)
@@ -2438,7 +2471,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (!ctnConst2.isNull() && !ctnConst2.getConst<bool>())
{
Node res = nm->mkConst(false);
- return returnRewrite(node, res, "ctn-rpl-non-ctn");
+ return returnRewrite(node, res, Rewrite::CTN_RPL_NON_CTN);
}
}
@@ -2470,7 +2503,7 @@ Node SequencesRewriter::rewriteContains(Node node)
{
ret = nm->mkNode(kind::EQUAL, node[0], node[1]);
}
- return returnRewrite(node, ret, "ctn-repl-self");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_SELF);
}
}
}
@@ -2482,7 +2515,7 @@ Node SequencesRewriter::rewriteContains(Node node)
{
// len( n2 ) > len( n1 ) => contains( n1, n2 ) ---> false
Node ret = NodeManager::currentNM()->mkConst(false);
- return returnRewrite(node, ret, "ctn-len-ineq");
+ return returnRewrite(node, ret, Rewrite::CTN_LEN_INEQ);
}
// multi-set reasoning
@@ -2492,14 +2525,14 @@ Node SequencesRewriter::rewriteContains(Node node)
if (checkEntailMultisetSubset(node[0], node[1]))
{
Node ret = nm->mkConst(false);
- return returnRewrite(node, ret, "ctn-mset-nss");
+ return returnRewrite(node, ret, Rewrite::CTN_MSET_NSS);
}
if (checkEntailArith(len_n2, len_n1, false))
{
// len( n2 ) >= len( n1 ) => contains( n1, n2 ) ---> n1 = n2
Node ret = node[0].eqNode(node[1]);
- return returnRewrite(node, ret, "ctn-len-ineq-nstrict");
+ return returnRewrite(node, ret, Rewrite::CTN_LEN_INEQ_NSTRICT);
}
// splitting
@@ -2537,7 +2570,7 @@ Node SequencesRewriter::rewriteContains(Node node)
NodeManager::currentNM()->mkNode(kind::STRING_STRCTN,
utils::mkConcat(spl[1], stype),
node[1]));
- return returnRewrite(node, ret, "ctn-split");
+ return returnRewrite(node, ret, Rewrite::CTN_SPLIT);
}
}
}
@@ -2552,7 +2585,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (node[0][2] == nm->mkNode(kind::STRING_LENGTH, node[1]))
{
Node ret = nm->mkNode(kind::EQUAL, node[0], node[1]);
- return returnRewrite(node, ret, "ctn-substr");
+ return returnRewrite(node, ret, Rewrite::CTN_SUBSTR);
}
}
else if (node[0].getKind() == kind::STRING_STRREPL)
@@ -2565,7 +2598,7 @@ Node SequencesRewriter::rewriteContains(Node node)
// (str.contains (str.replace x c1 c2) c3) ---> (str.contains x c3)
// if there is no overlap between c1 and c3 and none between c2 and c3
Node ret = nm->mkNode(STRING_STRCTN, node[0][0], node[1]);
- return returnRewrite(node, ret, "ctn-repl-cnsts-to-ctn");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_CNSTS_TO_CTN);
}
}
@@ -2575,7 +2608,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (node[0][1] == node[1])
{
Node ret = nm->mkNode(kind::STRING_STRCTN, node[0][0], node[1]);
- return returnRewrite(node, ret, "ctn-repl-to-ctn");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_TO_CTN);
}
// (str.contains (str.replace x y x) z) ---> (str.contains x z)
@@ -2583,7 +2616,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (checkEntailLengthOne(node[1]))
{
Node ret = nm->mkNode(kind::STRING_STRCTN, node[0][0], node[1]);
- return returnRewrite(node, ret, "ctn-repl-len-one-to-ctn");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_LEN_ONE_TO_CTN);
}
}
@@ -2594,7 +2627,7 @@ Node SequencesRewriter::rewriteContains(Node node)
Node ret = nm->mkNode(OR,
nm->mkNode(STRING_STRCTN, node[0][0], node[0][1]),
nm->mkNode(STRING_STRCTN, node[0][0], node[0][2]));
- return returnRewrite(node, ret, "ctn-repl-to-ctn-disj");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_TO_CTN_DISJ);
}
// (str.contains (str.replace x y z) w) --->
@@ -2610,7 +2643,7 @@ Node SequencesRewriter::rewriteContains(Node node)
kind::STRING_STRCTN,
nm->mkNode(kind::STRING_STRREPL, node[0][0], node[0][1], empty),
node[1]);
- return returnRewrite(node, ret, "ctn-repl-simp-repl");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_SIMP_REPL);
}
}
}
@@ -2622,7 +2655,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (node[0] == node[1][1] && node[1][0] == node[1][2])
{
Node ret = nm->mkNode(kind::STRING_STRCTN, node[0], node[1][0]);
- return returnRewrite(node, ret, "ctn-repl");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL);
}
// (str.contains x (str.replace "" x y)) --->
@@ -2635,7 +2668,7 @@ Node SequencesRewriter::rewriteContains(Node node)
if (node[0] == node[1][1] && node[1][0] == emp)
{
Node ret = nm->mkNode(kind::EQUAL, emp, node[1]);
- return returnRewrite(node, ret, "ctn-repl-empty");
+ return returnRewrite(node, ret, Rewrite::CTN_REPL_EMPTY);
}
}
@@ -2652,7 +2685,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
{
// z<0 implies str.indexof( x, y, z ) --> -1
Node negone = nm->mkConst(Rational(-1));
- return returnRewrite(node, negone, "idof-neg");
+ return returnRewrite(node, negone, Rewrite::IDOF_NEG);
}
// the string type
@@ -2670,7 +2703,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
// in our implementation, that accessing a position greater than
// rMaxInt is guaranteed to be out of bounds.
Node negone = nm->mkConst(Rational(-1));
- return returnRewrite(node, negone, "idof-max");
+ return returnRewrite(node, negone, Rewrite::IDOF_MAX);
}
Assert(node[2].getConst<Rational>().sgn() >= 0);
Node s = children0[0];
@@ -2681,12 +2714,12 @@ Node SequencesRewriter::rewriteIndexof(Node node)
if (ret != std::string::npos)
{
Node retv = nm->mkConst(Rational(static_cast<unsigned>(ret)));
- return returnRewrite(node, retv, "idof-find");
+ return returnRewrite(node, retv, Rewrite::IDOF_FIND);
}
else if (children0.size() == 1)
{
Node negone = nm->mkConst(Rational(-1));
- return returnRewrite(node, negone, "idof-nfind");
+ return returnRewrite(node, negone, Rewrite::IDOF_NFIND);
}
}
@@ -2698,21 +2731,21 @@ Node SequencesRewriter::rewriteIndexof(Node node)
{
// indexof( x, x, 0 ) --> 0
Node zero = nm->mkConst(Rational(0));
- return returnRewrite(node, zero, "idof-eq-cst-start");
+ return returnRewrite(node, zero, Rewrite::IDOF_EQ_CST_START);
}
}
if (checkEntailArith(node[2], true))
{
// y>0 implies indexof( x, x, y ) --> -1
Node negone = nm->mkConst(Rational(-1));
- return returnRewrite(node, negone, "idof-eq-nstart");
+ return returnRewrite(node, negone, Rewrite::IDOF_EQ_NSTART);
}
Node emp = nm->mkConst(CVC4::String(""));
if (node[0] != emp)
{
// indexof( x, x, z ) ---> indexof( "", "", z )
Node ret = nm->mkNode(STRING_STRIDOF, emp, emp, node[2]);
- return returnRewrite(node, ret, "idof-eq-norm");
+ return returnRewrite(node, ret, Rewrite::IDOF_EQ_NORM);
}
}
@@ -2727,7 +2760,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
if (checkEntailArith(len0, node[2]) && checkEntailArith(node[2]))
{
// len(x)>=z ^ z >=0 implies indexof( x, "", z ) ---> z
- return returnRewrite(node, node[2], "idof-emp-idof");
+ return returnRewrite(node, node[2], Rewrite::IDOF_EMP_IDOF);
}
}
}
@@ -2736,7 +2769,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
{
// len(x)-z < len(y) implies indexof( x, y, z ) ----> -1
Node negone = nm->mkConst(Rational(-1));
- return returnRewrite(node, negone, "idof-len");
+ return returnRewrite(node, negone, Rewrite::IDOF_LEN);
}
Node fstr = node[0];
@@ -2768,7 +2801,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
// str.indexof(str.++(x,y,z),y,0) ---> str.indexof(str.++(x,y),y,0)
Node nn = utils::mkConcat(children0, stype);
Node ret = nm->mkNode(kind::STRING_STRIDOF, nn, node[1], node[2]);
- return returnRewrite(node, ret, "idof-def-ctn");
+ return returnRewrite(node, ret, Rewrite::IDOF_DEF_CTN);
}
// Strip components from the beginning that are guaranteed not to match
@@ -2783,7 +2816,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
utils::mkConcat(children0, stype),
node[1],
node[2]));
- return returnRewrite(node, ret, "idof-strip-cnst-endpts");
+ return returnRewrite(node, ret, Rewrite::IDOF_STRIP_CNST_ENDPTS);
}
}
@@ -2802,14 +2835,14 @@ Node SequencesRewriter::rewriteIndexof(Node node)
nm->mkNode(kind::PLUS,
nm->mkNode(kind::MINUS, node[2], new_len),
nm->mkNode(kind::STRING_STRIDOF, nn, node[1], new_len));
- return returnRewrite(node, ret, "idof-strip-sym-len");
+ return returnRewrite(node, ret, Rewrite::IDOF_STRIP_SYM_LEN);
}
}
else
{
// str.contains( x, y ) --> false implies str.indexof(x,y,z) --> -1
Node negone = nm->mkConst(Rational(-1));
- return returnRewrite(node, negone, "idof-nctn");
+ return returnRewrite(node, negone, Rewrite::IDOF_NCTN);
}
}
else
@@ -2833,7 +2866,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
children.insert(children.end(), children0.begin(), children0.end());
Node nn = utils::mkConcat(children, stype);
Node res = nm->mkNode(kind::STRING_STRIDOF, nn, node[1], node[2]);
- return returnRewrite(node, res, "idof-norm-prefix");
+ return returnRewrite(node, res, Rewrite::IDOF_NORM_PREFIX);
}
}
}
@@ -2848,7 +2881,7 @@ Node SequencesRewriter::rewriteIndexof(Node node)
ret = nm->mkNode(STRING_STRIDOF, ret, node[1], node[2]);
// For example:
// str.indexof( str.++( x, "A" ), "B", 0 ) ---> str.indexof( x, "B", 0 )
- return returnRewrite(node, ret, "rpl-pull-endpt");
+ return returnRewrite(node, ret, Rewrite::RPL_PULL_ENDPT);
}
}
@@ -2864,7 +2897,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
if (node[1].isConst() && Word::isEmpty(node[1]))
{
Node ret = nm->mkNode(STRING_CONCAT, node[2], node[0]);
- return returnRewrite(node, ret, "rpl-rpl-empty");
+ return returnRewrite(node, ret, Rewrite::RPL_RPL_EMPTY);
}
// the string type
TypeNode stype = node.getType();
@@ -2881,7 +2914,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
{
if (children0.size() == 1)
{
- return returnRewrite(node, node[0], "rpl-const-nfind");
+ return returnRewrite(node, node[0], Rewrite::RPL_CONST_NFIND);
}
}
else
@@ -2900,7 +2933,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
}
children.insert(children.end(), children0.begin() + 1, children0.end());
Node ret = utils::mkConcat(children, stype);
- return returnRewrite(node, ret, "rpl-const-find");
+ return returnRewrite(node, ret, Rewrite::RPL_CONST_FIND);
}
}
@@ -2919,7 +2952,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
Node l1 = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[1]);
if (checkEntailArith(l1, l0))
{
- return returnRewrite(node, node[0], "rpl-rpl-len-id");
+ return returnRewrite(node, node[0], Rewrite::RPL_RPL_LEN_ID);
}
// (str.replace x y x) ---> (str.replace x (str.++ y1 ... yn) x)
@@ -2941,7 +2974,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
if (node[1] != nn1)
{
Node ret = nm->mkNode(STRING_STRREPL, node[0], nn1, node[2]);
- return returnRewrite(node, ret, "rpl-x-y-x-simp");
+ return returnRewrite(node, ret, Rewrite::RPL_X_Y_X_SIMP);
}
}
}
@@ -2974,7 +3007,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
cres.push_back(node[2]);
cres.insert(cres.end(), ce.begin(), ce.end());
Node ret = utils::mkConcat(cres, stype);
- return returnRewrite(node, ret, "rpl-cctn-rpl");
+ return returnRewrite(node, ret, Rewrite::RPL_CCTN_RPL);
}
else if (!ce.empty())
{
@@ -2991,14 +3024,14 @@ Node SequencesRewriter::rewriteReplace(Node node)
node[2]));
scc.insert(scc.end(), ce.begin(), ce.end());
Node ret = utils::mkConcat(scc, stype);
- return returnRewrite(node, ret, "rpl-cctn");
+ return returnRewrite(node, ret, Rewrite::RPL_CCTN);
}
}
}
else
{
// ~contains( t, s ) => ( replace( t, s, r ) ----> t )
- return returnRewrite(node, node[0], "rpl-nctn");
+ return returnRewrite(node, node[0], Rewrite::RPL_NCTN);
}
}
else if (cmp_conr.getKind() == kind::EQUAL || cmp_conr.getKind() == kind::AND)
@@ -3042,14 +3075,14 @@ Node SequencesRewriter::rewriteReplace(Node node)
if (nn1 != node[1] || nn2 != node[2])
{
Node res = nm->mkNode(kind::STRING_STRREPL, node[0], nn1, nn2);
- return returnRewrite(node, res, "rpl-emp-cnts-substs");
+ return returnRewrite(node, res, Rewrite::RPL_EMP_CNTS_SUBSTS);
}
}
if (nn2 != node[2])
{
Node res = nm->mkNode(kind::STRING_STRREPL, node[0], node[1], nn2);
- return returnRewrite(node, res, "rpl-cnts-substs");
+ return returnRewrite(node, res, Rewrite::RPL_CNTS_SUBSTS);
}
}
}
@@ -3075,7 +3108,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
node[2]));
cc.insert(cc.end(), ce.begin(), ce.end());
Node ret = utils::mkConcat(cc, stype);
- return returnRewrite(node, ret, "rpl-pull-endpt");
+ return returnRewrite(node, ret, Rewrite::RPL_PULL_ENDPT);
}
}
}
@@ -3117,7 +3150,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
node[0],
utils::mkConcat(children1, stype),
node[2]);
- return returnRewrite(node, res, "repl-subst-idx");
+ return returnRewrite(node, res, Rewrite::REPL_SUBST_IDX);
}
}
@@ -3165,7 +3198,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
nm->mkNode(kind::STRING_STRREPL, y, w, z),
y,
z);
- return returnRewrite(node, ret, "repl-repl-short-circuit");
+ return returnRewrite(node, ret, Rewrite::REPL_REPL_SHORT_CIRCUIT);
}
}
}
@@ -3178,7 +3211,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
if (node[1][0] == node[1][2] && node[1][0] == node[2])
{
// str.replace( x, str.replace( x, y, x ), x ) ---> x
- return returnRewrite(node, node[0], "repl-repl2-inv-id");
+ return returnRewrite(node, node[0], Rewrite::REPL_REPL2_INV_ID);
}
bool dualReplIteSuccess = false;
Node cmp_con2 = checkEntailContains(node[1][0], node[1][2]);
@@ -3212,7 +3245,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
nm->mkNode(STRING_STRCTN, node[0], node[1][1]),
node[0],
node[2]);
- return returnRewrite(node, res, "repl-dual-repl-ite");
+ return returnRewrite(node, res, Rewrite::REPL_DUAL_REPL_ITE);
}
}
@@ -3248,7 +3281,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
if (invSuccess)
{
Node res = nm->mkNode(kind::STRING_STRREPL, node[0], node[1][0], node[2]);
- return returnRewrite(node, res, "repl-repl2-inv");
+ return returnRewrite(node, res, Rewrite::REPL_REPL2_INV);
}
}
if (node[2].getKind() == STRING_STRREPL)
@@ -3262,7 +3295,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
{
Node res =
nm->mkNode(kind::STRING_STRREPL, node[0], node[1], node[2][0]);
- return returnRewrite(node, res, "repl-repl3-inv");
+ return returnRewrite(node, res, Rewrite::REPL_REPL3_INV);
}
}
if (node[2][0] == node[1])
@@ -3282,7 +3315,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
}
if (success)
{
- return returnRewrite(node, node[0], "repl-repl3-inv-id");
+ return returnRewrite(node, node[0], Rewrite::REPL_REPL3_INV_ID);
}
}
}
@@ -3329,7 +3362,7 @@ Node SequencesRewriter::rewriteReplace(Node node)
// second occurrence of x. Notice this is specific to single characters
// due to complications with finds that span multiple components for
// non-characters.
- return returnRewrite(node, ret, "repl-char-ncontrib-find");
+ return returnRewrite(node, ret, Rewrite::REPL_CHAR_NCONTRIB_FIND);
}
}
@@ -3356,7 +3389,7 @@ Node SequencesRewriter::rewriteReplaceAll(Node node)
Node t = node[1];
if (Word::isEmpty(s) || Word::isEmpty(t))
{
- return returnRewrite(node, node[0], "replall-empty-find");
+ return returnRewrite(node, node[0], Rewrite::REPLALL_EMPTY_FIND);
}
std::size_t sizeS = Word::getLength(s);
std::size_t sizeT = Word::getLength(t);
@@ -3381,7 +3414,7 @@ Node SequencesRewriter::rewriteReplaceAll(Node node)
} while (curr != std::string::npos && curr < sizeS);
// constant evaluation
Node res = utils::mkConcat(children, stype);
- return returnRewrite(node, res, "replall-const");
+ return returnRewrite(node, res, Rewrite::REPLALL_CONST);
}
// rewrites that apply to both replace and replaceall
@@ -3403,7 +3436,7 @@ Node SequencesRewriter::rewriteReplaceInternal(Node node)
if (node[1] == node[2])
{
- return returnRewrite(node, node[0], "rpl-id");
+ return returnRewrite(node, node[0], Rewrite::RPL_ID);
}
if (node[0] == node[1])
@@ -3411,7 +3444,7 @@ Node SequencesRewriter::rewriteReplaceInternal(Node node)
// only holds for replaceall if non-empty
if (nk == STRING_STRREPL || checkEntailNonEmpty(node[1]))
{
- return returnRewrite(node, node[2], "rpl-replace");
+ return returnRewrite(node, node[2], Rewrite::RPL_REPLACE);
}
}
@@ -3428,7 +3461,7 @@ Node SequencesRewriter::rewriteStrReverse(Node node)
std::vector<unsigned> nvec = node[0].getConst<String>().getVec();
std::reverse(nvec.begin(), nvec.end());
Node retNode = nm->mkConst(String(nvec));
- return returnRewrite(node, retNode, "str-conv-const");
+ return returnRewrite(node, retNode, Rewrite::STR_CONV_CONST);
}
else if (x.getKind() == STRING_CONCAT)
{
@@ -3440,13 +3473,13 @@ Node SequencesRewriter::rewriteStrReverse(Node node)
std::reverse(children.begin(), children.end());
// rev( x1 ++ x2 ) --> rev( x2 ) ++ rev( x1 )
Node retNode = nm->mkNode(STRING_CONCAT, children);
- return returnRewrite(node, retNode, "str-rev-minscope-concat");
+ return returnRewrite(node, retNode, Rewrite::STR_REV_MINSCOPE_CONCAT);
}
else if (x.getKind() == STRING_REV)
{
// rev( rev( x ) ) --> x
Node retNode = x[0];
- return returnRewrite(node, retNode, "str-rev-idem");
+ return returnRewrite(node, retNode, Rewrite::STR_REV_IDEM);
}
return node;
}
@@ -3459,7 +3492,7 @@ Node SequencesRewriter::rewritePrefixSuffix(Node n)
if (n[0] == n[1])
{
Node ret = NodeManager::currentNM()->mkConst(true);
- return returnRewrite(n, ret, "suf/prefix-eq");
+ return returnRewrite(n, ret, Rewrite::SUF_PREFIX_EQ);
}
if (n[0].isConst())
{
@@ -3467,7 +3500,7 @@ Node SequencesRewriter::rewritePrefixSuffix(Node n)
if (t.isEmptyString())
{
Node ret = NodeManager::currentNM()->mkConst(true);
- return returnRewrite(n, ret, "suf/prefix-empty-const");
+ return returnRewrite(n, ret, Rewrite::SUF_PREFIX_EMPTY_CONST);
}
}
if (n[1].isConst())
@@ -3487,12 +3520,12 @@ Node SequencesRewriter::rewritePrefixSuffix(Node n)
ret = NodeManager::currentNM()->mkConst(true);
}
}
- return returnRewrite(n, ret, "suf/prefix-const");
+ return returnRewrite(n, ret, Rewrite::SUF_PREFIX_CONST);
}
else if (lenS == 0)
{
Node ret = n[0].eqNode(n[1]);
- return returnRewrite(n, ret, "suf/prefix-empty");
+ return returnRewrite(n, ret, Rewrite::SUF_PREFIX_EMPTY);
}
else if (lenS == 1)
{
@@ -3500,7 +3533,7 @@ Node SequencesRewriter::rewritePrefixSuffix(Node n)
// (str.contains "A" x )
Node ret =
NodeManager::currentNM()->mkNode(kind::STRING_STRCTN, n[1], n[0]);
- return returnRewrite(n, ret, "suf/prefix-ctn");
+ return returnRewrite(n, ret, Rewrite::SUF_PREFIX_CTN);
}
}
Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, n[0]);
@@ -3520,14 +3553,14 @@ Node SequencesRewriter::rewritePrefixSuffix(Node n)
Node eqs = inferEqsFromContains(n[1], n[0]);
if (!eqs.isNull())
{
- return returnRewrite(n, eqs, "suf/prefix-to-eqs");
+ return returnRewrite(n, eqs, Rewrite::SUF_PREFIX_TO_EQS);
}
// general reduction to equality + substr
Node retNode = n[0].eqNode(
NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, n[1], val, lens));
- return retNode;
+ return returnRewrite(n, retNode, Rewrite::SUF_PREFIX_ELIM);
}
Node SequencesRewriter::splitConstant(Node a, Node b, int& index, bool isRev)
@@ -4196,7 +4229,7 @@ bool SequencesRewriter::stripConstantEndpoints(std::vector<Node>& n1,
return changed;
}
-Node SequencesRewriter::canonicalStrForSymbolicLength(Node len)
+Node SequencesRewriter::canonicalStrForSymbolicLength(Node len, TypeNode stype)
{
NodeManager* nm = NodeManager::currentNM();
@@ -4207,7 +4240,15 @@ Node SequencesRewriter::canonicalStrForSymbolicLength(Node len)
Rational ratLen = len.getConst<Rational>();
Assert(ratLen.getDenominator() == 1);
Integer intLen = ratLen.getNumerator();
- res = nm->mkConst(String(std::string(intLen.getUnsignedInt(), 'A')));
+ uint32_t u = intLen.getUnsignedInt();
+ if (stype.isString())
+ {
+ res = nm->mkConst(String(std::string(u, 'A')));
+ }
+ else
+ {
+ Unimplemented() << "canonicalStrForSymbolicLength for non-string";
+ }
}
else if (len.getKind() == kind::PLUS)
{
@@ -4215,7 +4256,7 @@ Node SequencesRewriter::canonicalStrForSymbolicLength(Node len)
NodeBuilder<> concatBuilder(kind::STRING_CONCAT);
for (const auto& n : len)
{
- Node sn = canonicalStrForSymbolicLength(n);
+ Node sn = canonicalStrForSymbolicLength(n, stype);
if (sn.isNull())
{
return Node::null();
@@ -4234,7 +4275,7 @@ Node SequencesRewriter::canonicalStrForSymbolicLength(Node len)
Assert(ratReps.getDenominator() == 1);
Integer intReps = ratReps.getNumerator();
- Node nRep = canonicalStrForSymbolicLength(len[1]);
+ Node nRep = canonicalStrForSymbolicLength(len[1], stype);
std::vector<Node> nRepChildren;
utils::getConcat(nRep, nRepChildren);
NodeBuilder<> concatBuilder(kind::STRING_CONCAT);
@@ -4256,7 +4297,7 @@ Node SequencesRewriter::lengthPreserveRewrite(Node n)
{
NodeManager* nm = NodeManager::currentNM();
Node len = Rewriter::rewrite(nm->mkNode(kind::STRING_LENGTH, n));
- Node res = canonicalStrForSymbolicLength(len);
+ Node res = canonicalStrForSymbolicLength(len, n.getType());
return res.isNull() ? n : res;
}
@@ -4833,8 +4874,6 @@ void SequencesRewriter::getArithApproximations(Node a,
bool SequencesRewriter::checkEntailMultisetSubset(Node a, Node b)
{
- NodeManager* nm = NodeManager::currentNM();
-
std::vector<Node> avec;
utils::getConcat(getMultisetApproximation(a), avec);
std::vector<Node> bvec;
@@ -4877,14 +4916,9 @@ bool SequencesRewriter::checkEntailMultisetSubset(Node a, Node b)
{
Node cn = ncp.first;
Assert(cn.isConst());
- std::vector<unsigned> cc_vec;
- const std::vector<unsigned>& cvec = cn.getConst<String>().getVec();
- for (unsigned i = 0, size = cvec.size(); i < size; i++)
+ std::vector<Node> cnChars = Word::getChars(cn);
+ for (const Node& ch : cnChars)
{
- // make the character
- cc_vec.clear();
- cc_vec.insert(cc_vec.end(), cvec.begin() + i, cvec.begin() + i + 1);
- Node ch = nm->mkConst(String(cc_vec));
count_const[j][ch] += ncp.second;
if (std::find(chars.begin(), chars.end(), ch) == chars.end())
{
@@ -4919,19 +4953,17 @@ bool SequencesRewriter::checkEntailMultisetSubset(Node a, Node b)
Node SequencesRewriter::checkEntailHomogeneousString(Node a)
{
- NodeManager* nm = NodeManager::currentNM();
-
std::vector<Node> avec;
utils::getConcat(getMultisetApproximation(a), avec);
bool cValid = false;
- unsigned c = 0;
+ Node c;
for (const Node& ac : avec)
{
if (ac.isConst())
{
- std::vector<unsigned> acv = ac.getConst<String>().getVec();
- for (unsigned cc : acv)
+ std::vector<Node> acv = Word::getChars(ac);
+ for (const Node& cc : acv)
{
if (!cValid)
{
@@ -4954,11 +4986,10 @@ Node SequencesRewriter::checkEntailHomogeneousString(Node a)
if (!cValid)
{
- return nm->mkConst(String(""));
+ return Word::mkEmptyWord(a.getType());
}
- std::vector<unsigned> cv = {c};
- return nm->mkConst(String(cv));
+ return c;
}
Node SequencesRewriter::getMultisetApproximation(Node a)
@@ -5568,9 +5599,9 @@ std::pair<bool, std::vector<Node> > SequencesRewriter::collectEmptyEqs(Node x)
allEmptyEqs, std::vector<Node>(emptyNodes.begin(), emptyNodes.end()));
}
-Node SequencesRewriter::returnRewrite(Node node, Node ret, const char* c)
+Node SequencesRewriter::returnRewrite(Node node, Node ret, Rewrite r)
{
- Trace("strings-rewrite") << "Rewrite " << node << " to " << ret << " by " << c
+ Trace("strings-rewrite") << "Rewrite " << node << " to " << ret << " by " << r
<< "." << std::endl;
NodeManager* nm = NodeManager::currentNM();
diff --git a/src/theory/strings/sequences_rewriter.h b/src/theory/strings/sequences_rewriter.h
index 5aba4ab6f..0e5cd5705 100644
--- a/src/theory/strings/sequences_rewriter.h
+++ b/src/theory/strings/sequences_rewriter.h
@@ -23,6 +23,7 @@
#include <vector>
#include "expr/attribute.h"
+#include "theory/strings/rewrites.h"
#include "theory/theory_rewriter.h"
#include "theory/type_enumerator.h"
@@ -120,6 +121,37 @@ class SequencesRewriter : public TheoryRewriter
* Returns the rewritten form of node.
*/
static Node rewriteLoopRegExp(TNode node);
+ /** rewrite regular expression repeat
+ *
+ * This is the entry point for post-rewriting applications of re.repeat.
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteRepeatRegExp(TNode node);
+ /** rewrite regular expression option
+ *
+ * This is the entry point for post-rewriting applications of re.opt.
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteOptionRegExp(TNode node);
+ /** rewrite regular expression plus
+ *
+ * This is the entry point for post-rewriting applications of re.+.
+ * Returns the rewritten form of node.
+ */
+ static Node rewritePlusRegExp(TNode node);
+ /** rewrite regular expression difference
+ *
+ * This is the entry point for post-rewriting applications of re.diff.
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteDifferenceRegExp(TNode node);
+ /** rewrite regular expression range
+ *
+ * This is the entry point for post-rewriting applications of re.range.
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteRangeRegExp(TNode node);
+
/** rewrite regular expression membership
*
* This is the entry point for post-rewriting applications of str.in.re
@@ -149,7 +181,7 @@ class SequencesRewriter : public TheoryRewriter
/**
* Called when node rewrites to ret.
*
- * The string c indicates the justification for the rewrite, which is printed
+ * The rewrite r indicates the justification for the rewrite, which is printed
* by this function for debugging.
*
* If node is not an equality and ret is an equality, this method applies
@@ -157,7 +189,7 @@ class SequencesRewriter : public TheoryRewriter
* additional rewrites on ret, after which we return the result of this call.
* Otherwise, this method simply returns ret.
*/
- static Node returnRewrite(Node node, Node ret, const char* c);
+ static Node returnRewrite(Node node, Node ret, Rewrite r);
public:
RewriteResponse postRewrite(TNode node) override;
@@ -181,12 +213,24 @@ class SequencesRewriter : public TheoryRewriter
* necessarily one of { s = t, t = s, true, false }.
*/
static Node rewriteEqualityExt(Node node);
+ /** rewrite string length
+ * This is the entry point for post-rewriting terms node of the form
+ * str.len( t )
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteLength(Node node);
/** rewrite concat
* This is the entry point for post-rewriting terms node of the form
* str.++( t1, .., tn )
* Returns the rewritten form of node.
*/
static Node rewriteConcat(Node node);
+ /** rewrite character at
+ * This is the entry point for post-rewriting terms node of the form
+ * str.charat( s, i1 )
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteCharAt(Node node);
/** rewrite substr
* This is the entry point for post-rewriting terms node of the form
* str.substr( s, i1, i2 )
@@ -468,11 +512,12 @@ class SequencesRewriter : public TheoryRewriter
int dir = 0);
/**
- * Given a symbolic length n, returns the canonical string for that length.
- * For example if n is constant, this function returns a string consisting of
- * "A" repeated n times. Returns the null node if no such string exists.
+ * Given a symbolic length n, returns the canonical string (of type stype)
+ * for that length. For example if n is constant, this function returns a
+ * string consisting of "A" repeated n times. Returns the null node if no such
+ * string exists.
*/
- static Node canonicalStrForSymbolicLength(Node n);
+ static Node canonicalStrForSymbolicLength(Node n, TypeNode stype);
/** length preserving rewrite
*
diff --git a/src/theory/strings/sequences_stats.cpp b/src/theory/strings/sequences_stats.cpp
index 0f1e93599..5cd844290 100644
--- a/src/theory/strings/sequences_stats.cpp
+++ b/src/theory/strings/sequences_stats.cpp
@@ -22,14 +22,51 @@ namespace theory {
namespace strings {
SequencesStatistics::SequencesStatistics()
- : d_inferences("theory::strings::inferences")
+ : d_inferences("theory::strings::inferences"),
+ d_cdSimplifications("theory::strings::cdSimplifications"),
+ d_reductions("theory::strings::reductions"),
+ d_regexpUnfoldingsPos("theory::strings::regexpUnfoldingsPos"),
+ d_regexpUnfoldingsNeg("theory::strings::regexpUnfoldingsNeg"),
+ d_conflictsEqEngine("theory::strings::conflictsEqEngine", 0),
+ d_conflictsEagerPrefix("theory::strings::conflictsEagerPrefix", 0),
+ d_conflictsInfer("theory::strings::conflictsInfer", 0),
+ d_lemmasEagerPreproc("theory::strings::lemmasEagerPreproc", 0),
+ d_lemmasCmiSplit("theory::strings::lemmasCmiSplit", 0),
+ d_lemmasRegisterTerm("theory::strings::lemmasRegisterTerm", 0),
+ d_lemmasRegisterTermAtomic("theory::strings::lemmasRegisterTermAtomic",
+ 0),
+ d_lemmasInfer("theory::strings::lemmasInfer", 0)
{
smtStatisticsRegistry()->registerStat(&d_inferences);
+ smtStatisticsRegistry()->registerStat(&d_cdSimplifications);
+ smtStatisticsRegistry()->registerStat(&d_reductions);
+ smtStatisticsRegistry()->registerStat(&d_regexpUnfoldingsPos);
+ smtStatisticsRegistry()->registerStat(&d_regexpUnfoldingsNeg);
+ smtStatisticsRegistry()->registerStat(&d_conflictsEqEngine);
+ smtStatisticsRegistry()->registerStat(&d_conflictsEagerPrefix);
+ smtStatisticsRegistry()->registerStat(&d_conflictsInfer);
+ smtStatisticsRegistry()->registerStat(&d_lemmasEagerPreproc);
+ smtStatisticsRegistry()->registerStat(&d_lemmasCmiSplit);
+ smtStatisticsRegistry()->registerStat(&d_lemmasRegisterTerm);
+ smtStatisticsRegistry()->registerStat(&d_lemmasRegisterTermAtomic);
+ smtStatisticsRegistry()->registerStat(&d_lemmasInfer);
}
SequencesStatistics::~SequencesStatistics()
{
smtStatisticsRegistry()->unregisterStat(&d_inferences);
+ smtStatisticsRegistry()->unregisterStat(&d_cdSimplifications);
+ smtStatisticsRegistry()->unregisterStat(&d_reductions);
+ smtStatisticsRegistry()->unregisterStat(&d_regexpUnfoldingsPos);
+ smtStatisticsRegistry()->unregisterStat(&d_regexpUnfoldingsNeg);
+ smtStatisticsRegistry()->unregisterStat(&d_conflictsEqEngine);
+ smtStatisticsRegistry()->unregisterStat(&d_conflictsEagerPrefix);
+ smtStatisticsRegistry()->unregisterStat(&d_conflictsInfer);
+ smtStatisticsRegistry()->unregisterStat(&d_lemmasEagerPreproc);
+ smtStatisticsRegistry()->unregisterStat(&d_lemmasCmiSplit);
+ smtStatisticsRegistry()->unregisterStat(&d_lemmasRegisterTerm);
+ smtStatisticsRegistry()->unregisterStat(&d_lemmasRegisterTermAtomic);
+ smtStatisticsRegistry()->unregisterStat(&d_lemmasInfer);
}
}
diff --git a/src/theory/strings/sequences_stats.h b/src/theory/strings/sequences_stats.h
index b55178f4c..65f50dbbc 100644
--- a/src/theory/strings/sequences_stats.h
+++ b/src/theory/strings/sequences_stats.h
@@ -17,6 +17,7 @@
#ifndef CVC4__THEORY__STRINGS__SEQUENCES_STATS_H
#define CVC4__THEORY__STRINGS__SEQUENCES_STATS_H
+#include "expr/kind.h"
#include "theory/strings/infer_info.h"
#include "util/statistics_registry.h"
@@ -24,17 +25,80 @@ namespace CVC4 {
namespace theory {
namespace strings {
+/**
+ * Statistics for the theory of strings.
+ *
+ * This is roughly broken up into the following parts:
+ * (1) Inferences,
+ * (2) Conflicts,
+ * (3) Lemmas.
+ *
+ * "Inferences" (1) are steps invoked during solving, which either trigger:
+ * (a) An internal update to the state of the solver (e.g. adding an inferred
+ * equality to the equality engine),
+ * (b) A call to OutputChannel::conflict,
+ * (c) A call to OutputChannel::lemma.
+ * For details, see InferenceManager. We track stats on each kind of
+ * inference that have been indicated by the solvers in TheoryStrings.
+ * Some kinds of inferences are further distinguished by the Kind of the node
+ * they operate on (see d_cdSimplifications, d_reductions, d_regexpUnfoldings).
+ *
+ * "Conflicts" (2) arise from various kinds of reasoning, listed below,
+ * where inferences are one of the possible methods for deriving conflicts.
+ *
+ * "Lemmas" (3) also arise from various kinds of reasoning, listed below,
+ * where inferences are one of the possible methods for deriving lemmas.
+ */
class SequencesStatistics
{
public:
SequencesStatistics();
~SequencesStatistics();
-
- /** Counts the number of inferences made of each type of inference */
+ //--------------- inferences
+ /** Counts the number of applications of each type of inference */
HistogramStat<Inference> d_inferences;
+ /**
+ * Counts the number of applications of each type of context-dependent
+ * simplification. The sum of this map is equal to the number of EXTF or
+ * EXTF_N inferences.
+ */
+ HistogramStat<Kind> d_cdSimplifications;
+ /**
+ * Counts the number of applications of each type of reduction. The sum of
+ * this map is equal to the number of REDUCTION inferences (when
+ * options::stringLazyPreproc is true).
+ */
+ HistogramStat<Kind> d_reductions;
+ /**
+ * Counts the number of applications of each type of regular expression
+ * positive (resp. negative) unfoldings. The sum of this map is equal to the
+ * number of RE_UNFOLD_POS (resp. RE_UNFOLD_NEG) inferences.
+ */
+ HistogramStat<Kind> d_regexpUnfoldingsPos;
+ HistogramStat<Kind> d_regexpUnfoldingsNeg;
+ //--------------- end of inferences
+ //--------------- conflicts, partition of calls to OutputChannel::conflict
+ /** Number of equality engine conflicts */
+ IntStat d_conflictsEqEngine;
+ /** Number of eager prefix conflicts */
+ IntStat d_conflictsEagerPrefix;
+ /** Number of inference conflicts */
+ IntStat d_conflictsInfer;
+ //--------------- end of conflicts
+ //--------------- lemmas, partition of calls to OutputChannel::lemma
+ /** Number of lemmas added due to eager preprocessing */
+ IntStat d_lemmasEagerPreproc;
+ /** Number of collect model info splits */
+ IntStat d_lemmasCmiSplit;
+ /** Number of lemmas added due to registering terms */
+ IntStat d_lemmasRegisterTerm;
+ /** Number of lemmas added due to registering atomic terms */
+ IntStat d_lemmasRegisterTermAtomic;
+ /** Number of lemmas added due to inferences */
+ IntStat d_lemmasInfer;
+ //--------------- end of lemmas
};
-
}
}
}
diff --git a/src/theory/strings/solver_state.cpp b/src/theory/strings/solver_state.cpp
index a38bf2c50..30acba9fd 100644
--- a/src/theory/strings/solver_state.cpp
+++ b/src/theory/strings/solver_state.cpp
@@ -108,7 +108,7 @@ void SolverState::eqNotifyNewClass(TNode t)
ei->d_codeTerm = t[0];
}
}
- else if (k == CONST_STRING)
+ else if (t.isConst())
{
EqcInfo* ei = getOrMakeEqcInfo(t);
ei->d_prefixC = t;
diff --git a/src/theory/strings/strings_fmf.cpp b/src/theory/strings/strings_fmf.cpp
index 8ca6d2de1..02af3949e 100644
--- a/src/theory/strings/strings_fmf.cpp
+++ b/src/theory/strings/strings_fmf.cpp
@@ -40,7 +40,7 @@ StringsFmf::~StringsFmf() {}
void StringsFmf::preRegisterTerm(TNode n)
{
- if (!n.getType().isString())
+ if (!n.getType().isStringLike())
{
return;
}
diff --git a/src/theory/strings/strings_rewriter.cpp b/src/theory/strings/strings_rewriter.cpp
index 75dfe7432..28ed14095 100644
--- a/src/theory/strings/strings_rewriter.cpp
+++ b/src/theory/strings/strings_rewriter.cpp
@@ -41,7 +41,7 @@ Node StringsRewriter::rewriteStrToInt(Node node)
{
ret = nm->mkConst(Rational(-1));
}
- return returnRewrite(node, ret, "stoi-eval");
+ return returnRewrite(node, ret, Rewrite::STOI_EVAL);
}
else if (node[0].getKind() == STRING_CONCAT)
{
@@ -53,7 +53,7 @@ Node StringsRewriter::rewriteStrToInt(Node node)
if (!t.isNumber())
{
Node ret = nm->mkConst(Rational(-1));
- return returnRewrite(node, ret, "stoi-concat-nonnum");
+ return returnRewrite(node, ret, Rewrite::STOI_CONCAT_NONNUM);
}
}
}
@@ -78,7 +78,7 @@ Node StringsRewriter::rewriteIntToStr(Node node)
Assert(stmp[0] != '-');
ret = nm->mkConst(String(stmp));
}
- return returnRewrite(node, ret, "itos-eval");
+ return returnRewrite(node, ret, Rewrite::ITOS_EVAL);
}
return node;
}
@@ -93,7 +93,7 @@ Node StringsRewriter::rewriteStrConvert(Node node)
std::vector<unsigned> nvec = node[0].getConst<String>().getVec();
for (unsigned i = 0, nvsize = nvec.size(); i < nvsize; i++)
{
- unsigned newChar = String::convertUnsignedIntToCode(nvec[i]);
+ unsigned newChar = nvec[i];
// transform it
// upper 65 ... 90
// lower 97 ... 122
@@ -111,11 +111,10 @@ Node StringsRewriter::rewriteStrConvert(Node node)
newChar = newChar + 32;
}
}
- newChar = String::convertCodeToUnsignedInt(newChar);
nvec[i] = newChar;
}
Node retNode = nm->mkConst(String(nvec));
- return returnRewrite(node, retNode, "str-conv-const");
+ return returnRewrite(node, retNode, Rewrite::STR_CONV_CONST);
}
else if (node[0].getKind() == STRING_CONCAT)
{
@@ -126,7 +125,7 @@ Node StringsRewriter::rewriteStrConvert(Node node)
}
// tolower( x1 ++ x2 ) --> tolower( x1 ) ++ tolower( x2 )
Node retNode = concatBuilder.constructNode();
- return returnRewrite(node, retNode, "str-conv-minscope-concat");
+ return returnRewrite(node, retNode, Rewrite::STR_CONV_MINSCOPE_CONCAT);
}
else if (node[0].getKind() == STRING_TOLOWER
|| node[0].getKind() == STRING_TOUPPER)
@@ -134,16 +133,26 @@ Node StringsRewriter::rewriteStrConvert(Node node)
// tolower( tolower( x ) ) --> tolower( x )
// tolower( toupper( x ) ) --> tolower( x )
Node retNode = nm->mkNode(nk, node[0][0]);
- return returnRewrite(node, retNode, "str-conv-idem");
+ return returnRewrite(node, retNode, Rewrite::STR_CONV_IDEM);
}
else if (node[0].getKind() == STRING_ITOS)
{
// tolower( str.from.int( x ) ) --> str.from.int( x )
- return returnRewrite(node, node[0], "str-conv-itos");
+ return returnRewrite(node, node[0], Rewrite::STR_CONV_ITOS);
}
return node;
}
+Node StringsRewriter::rewriteStringLt(Node n)
+{
+ Assert(n.getKind() == kind::STRING_LT);
+ NodeManager* nm = NodeManager::currentNM();
+ // eliminate s < t ---> s != t AND s <= t
+ Node retNode = nm->mkNode(
+ AND, n[0].eqNode(n[1]).negate(), nm->mkNode(STRING_LEQ, n[0], n[1]));
+ return returnRewrite(n, retNode, Rewrite::STR_LT_ELIM);
+}
+
Node StringsRewriter::rewriteStringLeq(Node n)
{
Assert(n.getKind() == kind::STRING_LEQ);
@@ -151,14 +160,14 @@ Node StringsRewriter::rewriteStringLeq(Node n)
if (n[0] == n[1])
{
Node ret = nm->mkConst(true);
- return returnRewrite(n, ret, "str-leq-id");
+ return returnRewrite(n, ret, Rewrite::STR_LEQ_ID);
}
if (n[0].isConst() && n[1].isConst())
{
String s = n[0].getConst<String>();
String t = n[1].getConst<String>();
Node ret = nm->mkConst(s.isLeq(t));
- return returnRewrite(n, ret, "str-leq-eval");
+ return returnRewrite(n, ret, Rewrite::STR_LEQ_EVAL);
}
// empty strings
for (unsigned i = 0; i < 2; i++)
@@ -166,7 +175,7 @@ Node StringsRewriter::rewriteStringLeq(Node n)
if (n[i].isConst() && n[i].getConst<String>().isEmptyString())
{
Node ret = i == 0 ? nm->mkConst(true) : n[0].eqNode(n[1]);
- return returnRewrite(n, ret, "str-leq-empty");
+ return returnRewrite(n, ret, Rewrite::STR_LEQ_EMPTY);
}
}
@@ -190,7 +199,7 @@ Node StringsRewriter::rewriteStringLeq(Node n)
if (!s.isLeq(t))
{
Node ret = nm->mkConst(false);
- return returnRewrite(n, ret, "str-leq-cprefix");
+ return returnRewrite(n, ret, Rewrite::STR_LEQ_CPREFIX);
}
}
return n;
@@ -214,7 +223,7 @@ Node StringsRewriter::rewriteStringFromCode(Node n)
{
ret = nm->mkConst(String(""));
}
- return returnRewrite(n, ret, "from-code-eval");
+ return returnRewrite(n, ret, Rewrite::FROM_CODE_EVAL);
}
return n;
}
@@ -231,17 +240,29 @@ Node StringsRewriter::rewriteStringToCode(Node n)
{
std::vector<unsigned> vec = s.getVec();
Assert(vec.size() == 1);
- ret = nm->mkConst(Rational(String::convertUnsignedIntToCode(vec[0])));
+ ret = nm->mkConst(Rational(vec[0]));
}
else
{
ret = nm->mkConst(Rational(-1));
}
- return returnRewrite(n, ret, "to-code-eval");
+ return returnRewrite(n, ret, Rewrite::TO_CODE_EVAL);
}
return n;
}
+Node StringsRewriter::rewriteStringIsDigit(Node n)
+{
+ Assert(n.getKind() == kind::STRING_IS_DIGIT);
+ NodeManager* nm = NodeManager::currentNM();
+ // eliminate str.is_digit(s) ----> 48 <= str.to_code(s) <= 57
+ Node t = nm->mkNode(STRING_TO_CODE, n[0]);
+ Node retNode = nm->mkNode(AND,
+ nm->mkNode(LEQ, nm->mkConst(Rational(48)), t),
+ nm->mkNode(LEQ, t, nm->mkConst(Rational(57))));
+ return returnRewrite(n, retNode, Rewrite::IS_DIGIT_ELIM);
+}
+
} // namespace strings
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/strings/strings_rewriter.h b/src/theory/strings/strings_rewriter.h
index e6a6b0693..0c5b0b2f8 100644
--- a/src/theory/strings/strings_rewriter.h
+++ b/src/theory/strings/strings_rewriter.h
@@ -56,6 +56,14 @@ class StringsRewriter : public SequencesRewriter
*/
static Node rewriteStrConvert(Node n);
+ /** rewrite string less than
+ *
+ * This is the entry point for post-rewriting terms n of the form
+ * str.<( t, s )
+ * Returns the rewritten form of n.
+ */
+ static Node rewriteStringLt(Node n);
+
/** rewrite string less than or equal
*
* This is the entry point for post-rewriting terms n of the form
@@ -79,6 +87,14 @@ class StringsRewriter : public SequencesRewriter
* Returns the rewritten form of n.
*/
static Node rewriteStringToCode(Node n);
+
+ /** rewrite is digit
+ *
+ * This is the entry point for post-rewriting terms n of the form
+ * str.is_digit( t )
+ * Returns the rewritten form of n.
+ */
+ static Node rewriteStringIsDigit(Node n);
};
} // namespace strings
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 1006076d5..d5eb2dbbd 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -26,6 +26,7 @@
#include "smt/smt_statistics_registry.h"
#include "theory/ext_theory.h"
#include "theory/rewriter.h"
+#include "theory/strings/sequences_rewriter.h"
#include "theory/strings/theory_strings_utils.h"
#include "theory/strings/type_enumerator.h"
#include "theory/strings/word.h"
@@ -69,7 +70,7 @@ TheoryStrings::TheoryStrings(context::Context* c,
const LogicInfo& logicInfo)
: Theory(THEORY_STRINGS, c, u, out, valuation, logicInfo),
d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::strings", true),
+ d_equalityEngine(d_notify, c, "theory::strings::ee", true),
d_state(c, d_equalityEngine, d_valuation),
d_im(*this, c, u, d_state, d_sk_cache, out, d_statistics),
d_pregistered_terms_cache(u),
@@ -85,9 +86,17 @@ TheoryStrings::TheoryStrings(context::Context* c,
{
setupExtTheory();
ExtTheory* extt = getExtTheory();
- d_esolver.reset(new ExtfSolver(
- c, u, d_state, d_im, d_sk_cache, d_bsolver, d_csolver, extt));
- d_rsolver.reset(new RegExpSolver(*this, d_state, d_im, *d_esolver, c, u));
+ d_esolver.reset(new ExtfSolver(c,
+ u,
+ d_state,
+ d_im,
+ d_sk_cache,
+ d_bsolver,
+ d_csolver,
+ extt,
+ d_statistics));
+ d_rsolver.reset(
+ new RegExpSolver(*this, d_state, d_im, *d_esolver, d_statistics, c, u));
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
@@ -122,6 +131,11 @@ TheoryStrings::~TheoryStrings() {
}
+std::unique_ptr<TheoryRewriter> TheoryStrings::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new SequencesRewriter());
+}
+
bool TheoryStrings::areCareDisequal( TNode x, TNode y ) {
Assert(d_equalityEngine.hasTerm(x));
Assert(d_equalityEngine.hasTerm(y));
@@ -375,7 +389,7 @@ bool TheoryStrings::collectModelInfoType(
ctv.getConst<Rational>().getNumerator().toUnsignedInt();
Trace("strings-model") << "(code: " << cvalue << ") ";
std::vector<unsigned> vec;
- vec.push_back(String::convertCodeToUnsignedInt(cvalue));
+ vec.push_back(cvalue);
Node mv = nm->mkConst(String(vec));
pure_eq_assign[eqc] = mv;
m->getEqualityEngine()->addTerm(mv);
@@ -464,6 +478,7 @@ bool TheoryStrings::collectModelInfoType(
for (const Node& sl : len_splits)
{
Node spl = nm->mkNode(OR, sl, sl.negate());
+ ++(d_statistics.d_lemmasCmiSplit);
d_out->lemma(spl);
}
return false;
@@ -700,7 +715,8 @@ void TheoryStrings::check(Effort e) {
Trace("strings-eqc") << (t==0 ? "STRINGS:" : "OTHER:") << std::endl;
while( !eqcs2_i.isFinished() ){
Node eqc = (*eqcs2_i);
- bool print = (t==0 && eqc.getType().isString() ) || (t==1 && !eqc.getType().isString() );
+ bool print = (t == 0 && eqc.getType().isStringLike())
+ || (t == 1 && !eqc.getType().isStringLike());
if (print) {
eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
Trace("strings-eqc") << "Eqc( " << eqc << " ) : { ";
@@ -778,6 +794,7 @@ void TheoryStrings::conflict(TNode a, TNode b){
Node conflictNode;
conflictNode = explain( a.eqNode(b) );
Trace("strings-conflict") << "CONFLICT: Eq engine conflict : " << conflictNode << std::endl;
+ ++(d_statistics.d_conflictsEqEngine);
d_out->conflict( conflictNode );
}
}
@@ -872,7 +889,9 @@ void TheoryStrings::addCarePairs(TNodeTrie* t1,
void TheoryStrings::computeCareGraph(){
//computing the care graph here is probably still necessary, due to operators that take non-string arguments TODO: verify
Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Build term indices..." << std::endl;
- std::map<Node, TNodeTrie> index;
+ // Term index for each (type, operator) pair. We require the operator here
+ // since operators are polymorphic, taking strings/sequences.
+ std::map<std::pair<TypeNode, Node>, TNodeTrie> index;
std::map< Node, unsigned > arity;
unsigned functionTerms = d_functionsTerms.size();
for (unsigned i = 0; i < functionTerms; ++ i) {
@@ -888,16 +907,19 @@ void TheoryStrings::computeCareGraph(){
}
}
if( has_trigger_arg ){
- index[op].addTerm( f1, reps );
+ TypeNode ft = utils::getOwnerStringType(f1);
+ std::pair<TypeNode, Node> ikey = std::pair<TypeNode, Node>(ft, op);
+ index[ikey].addTerm(f1, reps);
arity[op] = reps.size();
}
}
//for each index
- for (std::pair<const Node, TNodeTrie>& tt : index)
+ for (std::pair<const std::pair<TypeNode, Node>, TNodeTrie>& ti : index)
{
Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Process index "
- << tt.first << "..." << std::endl;
- addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
+ << ti.first << "..." << std::endl;
+ Node op = ti.first.second;
+ addCarePairs(&ti.second, nullptr, arity[op], 0);
}
}
@@ -907,7 +929,9 @@ void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) {
if( atom.getKind()==kind::EQUAL ){
Trace("strings-pending-debug") << " Register term" << std::endl;
for( unsigned j=0; j<2; j++ ) {
- if( !d_equalityEngine.hasTerm( atom[j] ) && atom[j].getType().isString() ) {
+ if (!d_equalityEngine.hasTerm(atom[j])
+ && atom[j].getType().isStringLike())
+ {
registerTerm( atom[j], 0 );
}
}
@@ -939,6 +963,7 @@ void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) {
d_state.setConflict();
Trace("strings-conflict")
<< "CONFLICT: Eager prefix : " << conflictNode << std::endl;
+ ++(d_statistics.d_conflictsEagerPrefix);
d_out->conflict(conflictNode);
}
}
@@ -1047,7 +1072,7 @@ void TheoryStrings::registerTerm(Node n, int effort)
{
TypeNode tn = n.getType();
bool do_register = true;
- if (!tn.isString())
+ if (!tn.isStringLike())
{
if (options::stringEagerLen())
{
@@ -1070,37 +1095,41 @@ void TheoryStrings::registerTerm(Node n, int effort)
NodeManager* nm = NodeManager::currentNM();
Debug("strings-register") << "TheoryStrings::registerTerm() " << n
<< ", effort = " << effort << std::endl;
- if (tn.isString())
+ Node regTermLem;
+ if (tn.isStringLike())
{
// register length information:
// for variables, split on empty vs positive length
// for concat/const/replace, introduce proxy var and state length relation
- d_im.registerLength(n);
+ regTermLem = d_im.registerTerm(n);
}
else if (n.getKind() == STRING_TO_CODE)
{
d_has_str_code = true;
- // ite( str.len(s)==1, 0 <= str.code(s) < num_codes, str.code(s)=-1 )
+ // ite( str.len(s)==1, 0 <= str.code(s) < |A|, str.code(s)=-1 )
Node code_len = utils::mkNLength(n[0]).eqNode(d_one);
Node code_eq_neg1 = n.eqNode(d_neg_one);
Node code_range = nm->mkNode(
AND,
nm->mkNode(GEQ, n, d_zero),
- nm->mkNode(LT, n, nm->mkConst(Rational(CVC4::String::num_codes()))));
- Node lem = nm->mkNode(ITE, code_len, code_range, code_eq_neg1);
- Trace("strings-lemma") << "Strings::Lemma CODE : " << lem << std::endl;
- Trace("strings-assert") << "(assert " << lem << ")" << std::endl;
- d_out->lemma(lem);
+ nm->mkNode(
+ LT, n, nm->mkConst(Rational(utils::getAlphabetCardinality()))));
+ regTermLem = nm->mkNode(ITE, code_len, code_range, code_eq_neg1);
}
else if (n.getKind() == STRING_STRIDOF)
{
Node len = utils::mkNLength(n[0]);
- Node lem = nm->mkNode(AND,
- nm->mkNode(GEQ, n, nm->mkConst(Rational(-1))),
- nm->mkNode(LEQ, n, len));
- Trace("strings-lemma") << "Strings::Lemma IDOF range : " << lem
+ regTermLem = nm->mkNode(AND,
+ nm->mkNode(GEQ, n, nm->mkConst(Rational(-1))),
+ nm->mkNode(LEQ, n, len));
+ }
+ if (!regTermLem.isNull())
+ {
+ Trace("strings-lemma") << "Strings::Lemma REG-TERM : " << regTermLem
<< std::endl;
- d_out->lemma(lem);
+ Trace("strings-assert") << "(assert " << regTermLem << ")" << std::endl;
+ ++(d_statistics.d_lemmasRegisterTerm);
+ d_out->lemma(regTermLem);
}
}
@@ -1145,6 +1174,7 @@ Node TheoryStrings::ppRewrite(TNode atom) {
Trace("strings-ppr") << " rewrote " << atom << " -> " << ret << ", with " << new_nodes.size() << " lemmas." << std::endl;
for( unsigned i=0; i<new_nodes.size(); i++ ){
Trace("strings-ppr") << " lemma : " << new_nodes[i] << std::endl;
+ ++(d_statistics.d_lemmasEagerPreproc);
d_out->lemma( new_nodes[i] );
}
return ret;
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index 76c8f0469..0e95628bc 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -109,6 +109,8 @@ class TheoryStrings : public Theory {
const LogicInfo& logicInfo);
~TheoryStrings();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
std::string identify() const override { return std::string("TheoryStrings"); }
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index d4183700d..7777b9bd7 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -23,6 +23,7 @@
#include "proof/proof_manager.h"
#include "smt/logic_exception.h"
#include "theory/strings/sequences_rewriter.h"
+#include "theory/strings/word.h"
using namespace CVC4;
using namespace CVC4::kind;
@@ -31,14 +32,15 @@ namespace CVC4 {
namespace theory {
namespace strings {
-StringsPreprocess::StringsPreprocess(SkolemCache *sc, context::UserContext *u)
- : d_sc(sc)
+StringsPreprocess::StringsPreprocess(SkolemCache* sc,
+ context::UserContext* u,
+ SequencesStatistics& stats)
+ : d_sc(sc), d_statistics(stats)
{
//Constants
d_zero = NodeManager::currentNM()->mkConst(Rational(0));
d_one = NodeManager::currentNM()->mkConst(Rational(1));
d_neg_one = NodeManager::currentNM()->mkConst(Rational(-1));
- d_empty_str = NodeManager::currentNM()->mkConst(String(""));
}
StringsPreprocess::~StringsPreprocess(){
@@ -68,11 +70,13 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node c3 = nm->mkNode(GT, m, d_zero);
Node cond = nm->mkNode(AND, c1, c2, c3);
- Node sk1 = n == d_zero ? d_empty_str
+ Node emp = Word::mkEmptyWord(t.getType());
+
+ Node sk1 = n == d_zero ? emp
: d_sc->mkSkolemCached(
s, n, SkolemCache::SK_PREFIX, "sspre");
Node sk2 = SequencesRewriter::checkEntailArith(t12, lt0)
- ? d_empty_str
+ ? emp
: d_sc->mkSkolemCached(
s, t12, SkolemCache::SK_SUFFIX_REM, "sssufr");
Node b11 = s.eqNode(nm->mkNode(STRING_CONCAT, sk1, skt, sk2));
@@ -89,7 +93,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node b14 = nm->mkNode(LEQ, nm->mkNode(STRING_LENGTH, skt), m);
Node b1 = nm->mkNode(AND, b11, b12, b13, b14);
- Node b2 = skt.eqNode(d_empty_str);
+ Node b2 = skt.eqNode(emp);
Node lemma = nm->mkNode(ITE, cond, b1, b2);
// assert:
@@ -149,7 +153,8 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node cc1 = skk.eqNode(negone);
// y = ""
- Node cond2 = y.eqNode(d_empty_str);
+ Node emp = Word::mkEmptyWord(x.getType());
+ Node cond2 = y.eqNode(emp);
// skk = n
Node cc2 = skk.eqNode(t[2]);
@@ -237,8 +242,8 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node nonneg = nm->mkNode(GEQ, n, d_zero);
- lem = nm->mkNode(
- ITE, nonneg, nm->mkNode(AND, conc), itost.eqNode(d_empty_str));
+ Node emp = Word::mkEmptyWord(t.getType());
+ lem = nm->mkNode(ITE, nonneg, nm->mkNode(AND, conc), itost.eqNode(emp));
new_nodes.push_back(lem);
// assert:
// IF n>=0
@@ -275,7 +280,8 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Node lem = stoit.eqNode(d_neg_one);
conc1.push_back(lem);
- Node sEmpty = s.eqNode(d_empty_str);
+ Node emp = Word::mkEmptyWord(s.getType());
+ Node sEmpty = s.eqNode(emp);
Node k = nm->mkSkolem("k", nm->integerType());
Node kc1 = nm->mkNode(GEQ, k, d_zero);
Node kc2 = nm->mkNode(LT, k, lens);
@@ -476,8 +482,9 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
// the index to begin searching in x for y after the i^th occurrence of y in
// x, and Us( i ) is the result of processing the remainder after processing
// the i^th occurrence of y in x.
- Node assert = nm->mkNode(
- ITE, y.eqNode(d_empty_str), rpaw.eqNode(x), nm->mkNode(AND, lem));
+ Node emp = Word::mkEmptyWord(t.getType());
+ Node assert =
+ nm->mkNode(ITE, y.eqNode(emp), rpaw.eqNode(x), nm->mkNode(AND, lem));
new_nodes.push_back(assert);
// Thus, replaceall( x, y, z ) = rpaw
@@ -637,6 +644,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
Trace("strings-preprocess") << " " << new_nodes[i] << std::endl;
}
}
+ d_statistics.d_reductions << t.getKind();
}
else
{
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
index b96d619ef..fb6404aa6 100644
--- a/src/theory/strings/theory_strings_preprocess.h
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -22,6 +22,7 @@
#include <vector>
#include "context/cdhashmap.h"
#include "theory/rewriter.h"
+#include "theory/strings/sequences_stats.h"
#include "theory/strings/skolem_cache.h"
#include "theory/theory.h"
#include "util/hash.h"
@@ -38,48 +39,51 @@ namespace strings {
* reductions" inference schema of TheoryStrings.
*/
class StringsPreprocess {
-public:
- StringsPreprocess(SkolemCache *sc, context::UserContext *u);
- ~StringsPreprocess();
- /**
- * Returns a node t' such that
- * (exists k) new_nodes => t = t'
- * is valid, where k are the free skolems introduced when constructing
- * new_nodes.
- */
- Node simplify(Node t, std::vector<Node> &new_nodes);
- /**
- * Applies simplifyRec on t until a fixed point is reached, and returns
- * the resulting term t', which is such that
- * (exists k) new_nodes => t = t'
- * is valid, where k are the free skolems introduced when constructing
- * new_nodes.
- */
- Node processAssertion(Node t, std::vector<Node> &new_nodes);
- /**
- * Replaces all formulas t in vec_node with an equivalent formula t' that
- * contains no free instances of extended functions (that is, extended
- * functions may only appear beneath quantifiers). This applies simplifyRec
- * on each assertion in vec_node until a fixed point is reached.
- */
- void processAssertions(std::vector<Node> &vec_node);
+ public:
+ StringsPreprocess(SkolemCache* sc,
+ context::UserContext* u,
+ SequencesStatistics& stats);
+ ~StringsPreprocess();
+ /**
+ * Returns a node t' such that
+ * (exists k) new_nodes => t = t'
+ * is valid, where k are the free skolems introduced when constructing
+ * new_nodes.
+ */
+ Node simplify(Node t, std::vector<Node>& new_nodes);
+ /**
+ * Applies simplifyRec on t until a fixed point is reached, and returns
+ * the resulting term t', which is such that
+ * (exists k) new_nodes => t = t'
+ * is valid, where k are the free skolems introduced when constructing
+ * new_nodes.
+ */
+ Node processAssertion(Node t, std::vector<Node>& new_nodes);
+ /**
+ * Replaces all formulas t in vec_node with an equivalent formula t' that
+ * contains no free instances of extended functions (that is, extended
+ * functions may only appear beneath quantifiers). This applies simplifyRec
+ * on each assertion in vec_node until a fixed point is reached.
+ */
+ void processAssertions(std::vector<Node>& vec_node);
-private:
- /** commonly used constants */
- Node d_zero;
- Node d_one;
- Node d_neg_one;
- Node d_empty_str;
- /** pointer to the skolem cache used by this class */
- SkolemCache *d_sc;
- /**
- * Applies simplify to all top-level extended function subterms of t. New
- * assertions created in this reduction are added to new_nodes. The argument
- * visited stores a cache of previous results.
- */
- Node simplifyRec(Node t,
- std::vector<Node> &new_nodes,
- std::map<Node, Node> &visited);
+ private:
+ /** commonly used constants */
+ Node d_zero;
+ Node d_one;
+ Node d_neg_one;
+ /** pointer to the skolem cache used by this class */
+ SkolemCache* d_sc;
+ /** Reference to the statistics for the theory of strings/sequences. */
+ SequencesStatistics& d_statistics;
+ /**
+ * Applies simplify to all top-level extended function subterms of t. New
+ * assertions created in this reduction are added to new_nodes. The argument
+ * visited stores a cache of previous results.
+ */
+ Node simplifyRec(Node t,
+ std::vector<Node>& new_nodes,
+ std::map<Node, Node>& visited);
};
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
index 6abb57504..93a32f26e 100644
--- a/src/theory/strings/theory_strings_type_rules.h
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -291,14 +291,15 @@ public:
if (!t.isString()) {
throw TypeCheckingExceptionPrivate(n, "expecting a string term in regexp range");
}
- if( (*it).getKind() != kind::CONST_STRING ) {
+ if (!(*it).isConst())
+ {
throw TypeCheckingExceptionPrivate(n, "expecting a constant string term in regexp range");
}
if( (*it).getConst<String>().size() != 1 ) {
throw TypeCheckingExceptionPrivate(n, "expecting a single constant string term in regexp range");
}
unsigned ci = (*it).getConst<String>().front();
- ch[i] = String::convertUnsignedIntToCode(ci);
+ ch[i] = ci;
++it;
}
if(ch[0] > ch[1]) {
diff --git a/src/theory/strings/theory_strings_utils.cpp b/src/theory/strings/theory_strings_utils.cpp
index 5d27b8e2b..3b4c757f2 100644
--- a/src/theory/strings/theory_strings_utils.cpp
+++ b/src/theory/strings/theory_strings_utils.cpp
@@ -232,11 +232,10 @@ void getRegexpComponents(Node r, std::vector<Node>& result)
}
else if (r.getKind() == STRING_TO_REGEXP && r[0].isConst())
{
- String s = r[0].getConst<String>();
- for (size_t i = 0, size = s.size(); i < size; i++)
+ size_t rlen = Word::getLength(r[0]);
+ for (size_t i = 0; i < rlen; i++)
{
- result.push_back(
- nm->mkNode(STRING_TO_REGEXP, nm->mkConst(s.substr(i, 1))));
+ result.push_back(nm->mkNode(STRING_TO_REGEXP, Word::substr(r[0], i, 1)));
}
}
else
@@ -264,6 +263,54 @@ void printConcatTrace(std::vector<Node>& n, const char* c)
Trace(c) << ss.str();
}
+bool isStringKind(Kind k)
+{
+ return k == STRING_STOI || k == STRING_ITOS || k == STRING_TOLOWER
+ || k == STRING_TOUPPER || k == STRING_LEQ || k == STRING_LT
+ || k == STRING_FROM_CODE || k == STRING_TO_CODE;
+}
+
+TypeNode getOwnerStringType(Node n)
+{
+ TypeNode tn;
+ Kind k = n.getKind();
+ if (k == STRING_STRIDOF || k == STRING_LENGTH || k == STRING_STRCTN
+ || k == STRING_PREFIX || k == STRING_SUFFIX)
+ {
+ // owning string type is the type of first argument
+ tn = n[0].getType();
+ }
+ else if (isStringKind(k))
+ {
+ tn = NodeManager::currentNM()->stringType();
+ }
+ else
+ {
+ tn = n.getType();
+ }
+ AlwaysAssert(tn.isStringLike())
+ << "Unexpected term in getOwnerStringType : " << n << ", type " << tn;
+ return tn;
+}
+
+unsigned getRepeatAmount(TNode node)
+{
+ Assert(node.getKind() == REGEXP_REPEAT);
+ return node.getOperator().getConst<RegExpRepeat>().d_repeatAmount;
+}
+
+unsigned getLoopMaxOccurrences(TNode node)
+{
+ Assert(node.getKind() == REGEXP_LOOP);
+ return node.getOperator().getConst<RegExpLoop>().d_loopMaxOcc;
+}
+
+unsigned getLoopMinOccurrences(TNode node)
+{
+ Assert(node.getKind() == REGEXP_LOOP);
+ return node.getOperator().getConst<RegExpLoop>().d_loopMinOcc;
+}
+
} // namespace utils
} // namespace strings
} // namespace theory
diff --git a/src/theory/strings/theory_strings_utils.h b/src/theory/strings/theory_strings_utils.h
index 5f18d3936..846d3d563 100644
--- a/src/theory/strings/theory_strings_utils.h
+++ b/src/theory/strings/theory_strings_utils.h
@@ -140,6 +140,27 @@ void printConcat(std::ostream& out, std::vector<Node>& n);
/** Print the vector n as a concatentation term on trace given by c */
void printConcatTrace(std::vector<Node>& n, const char* c);
+/** Is k a string-specific kind? */
+bool isStringKind(Kind k);
+
+/** Get owner string type
+ *
+ * This returns a string-like type for a term n that belongs to the theory of
+ * strings. This type conceptually represents the subtheory of strings
+ * (Sequence(T) or String) that owns n. This is typically the type of n,
+ * but for instance, operators like str.indexof( s, t, n ), this is the type
+ * of s.
+ */
+TypeNode getOwnerStringType(Node n);
+
+/* Get the number of repetitions for a regexp repeat node */
+unsigned getRepeatAmount(TNode node);
+
+/* Get the maximum occurrences of given regexp loop node. */
+unsigned getLoopMaxOccurrences(TNode node);
+/* Get the minimum occurrences of given regexp loop node. */
+unsigned getLoopMinOccurrences(TNode node);
+
} // namespace utils
} // namespace strings
} // namespace theory
diff --git a/src/theory/strings/type_enumerator.cpp b/src/theory/strings/type_enumerator.cpp
index 12cf899b4..d24206860 100644
--- a/src/theory/strings/type_enumerator.cpp
+++ b/src/theory/strings/type_enumerator.cpp
@@ -15,12 +15,50 @@
#include "theory/strings/type_enumerator.h"
#include "theory/strings/theory_strings_utils.h"
-#include "util/regexp.h"
+#include "util/string.h"
namespace CVC4 {
namespace theory {
namespace strings {
+Node makeStandardModelConstant(const std::vector<unsigned>& vec,
+ uint32_t cardinality)
+{
+ std::vector<unsigned> mvec;
+ // if we contain all of the printable characters
+ if (cardinality >= 255)
+ {
+ for (unsigned i = 0, vsize = vec.size(); i < vsize; i++)
+ {
+ unsigned curr = vec[i];
+ // convert
+ Assert(vec[i] < cardinality);
+ if (vec[i] <= 61)
+ {
+ // first 62 printable characters [\u{65}-\u{126}]: 'A', 'B', 'C', ...
+ curr = vec[i] + 65;
+ }
+ else if (vec[i] <= 94)
+ {
+ // remaining 33 printable characters [\u{32}-\u{64}]: ' ', '!', '"', ...
+ curr = vec[i] - 30;
+ }
+ else
+ {
+ // the remaining characters, starting with \u{127} and wrapping around
+ // the first 32 non-printable characters.
+ curr = (vec[i] + 32) % cardinality;
+ }
+ mvec.push_back(curr);
+ }
+ }
+ else
+ {
+ mvec = vec;
+ }
+ return NodeManager::currentNM()->mkConst(String(mvec));
+}
+
WordIter::WordIter(uint32_t startLength) : d_hasEndLength(false), d_endLength(0)
{
for (uint32_t i = 0; i < startLength; i++)
@@ -117,7 +155,7 @@ bool StringEnumLen::increment()
void StringEnumLen::mkCurr()
{
- d_curr = NodeManager::currentNM()->mkConst(String(d_witer->getData()));
+ d_curr = makeStandardModelConstant(d_witer->getData(), d_cardinality);
}
StringEnumerator::StringEnumerator(TypeNode type, TypeEnumeratorProperties* tep)
diff --git a/src/theory/strings/type_enumerator.h b/src/theory/strings/type_enumerator.h
index 2061628a5..b379ce5c3 100644
--- a/src/theory/strings/type_enumerator.h
+++ b/src/theory/strings/type_enumerator.h
@@ -28,6 +28,26 @@ namespace theory {
namespace strings {
/**
+ * Make standard model constant
+ *
+ * In our string representation, we represent characters using vectors
+ * of unsigned integers indicating code points for the characters of that
+ * string.
+ *
+ * To make models user-friendly, we make unsigned integer 0 correspond to the
+ * 65th character ("A") in the ASCII alphabet to make models intuitive. In
+ * particular, say if we have a set of string variables that are distinct but
+ * otherwise unconstrained, then the model may assign them "A", "B", "C", ...
+ *
+ * @param vec The code points of the string in a given model,
+ * @param cardinality The cardinality of the alphabet,
+ * @return A string whose characters have the code points corresponding
+ * to vec in the standard model construction described above.
+ */
+Node makeStandardModelConstant(const std::vector<unsigned>& vec,
+ uint32_t cardinality);
+
+/**
* Generic iteration over vectors of indices of a given start/end length.
*/
class WordIter
diff --git a/src/theory/strings/word.cpp b/src/theory/strings/word.cpp
index dd573b68c..b42cf3160 100644
--- a/src/theory/strings/word.cpp
+++ b/src/theory/strings/word.cpp
@@ -14,7 +14,7 @@
#include "theory/strings/word.h"
-#include "util/regexp.h"
+#include "util/string.h"
using namespace CVC4::kind;
@@ -76,6 +76,29 @@ size_t Word::getLength(TNode x)
return 0;
}
+std::vector<Node> Word::getChars(TNode x)
+{
+ Kind k = x.getKind();
+ if (k == CONST_STRING)
+ {
+ std::vector<Node> ret;
+ NodeManager* nm = NodeManager::currentNM();
+ std::vector<unsigned> ccVec;
+ const std::vector<unsigned>& cvec = x.getConst<String>().getVec();
+ for (unsigned chVal : cvec)
+ {
+ ccVec.clear();
+ ccVec.push_back(chVal);
+ Node ch = nm->mkConst(String(ccVec));
+ ret.push_back(ch);
+ }
+ return ret;
+ }
+ Unimplemented();
+ std::vector<Node> ret;
+ return ret;
+}
+
bool Word::isEmpty(TNode x) { return getLength(x) == 0; }
bool Word::strncmp(TNode x, TNode y, std::size_t n)
diff --git a/src/theory/strings/word.h b/src/theory/strings/word.h
index 7b813a0b2..8e6e7876e 100644
--- a/src/theory/strings/word.h
+++ b/src/theory/strings/word.h
@@ -42,6 +42,13 @@ class Word
/** Return the length of word x */
static size_t getLength(TNode x);
+ /** Get characters
+ *
+ * Given word x, this returns the vector of words of length one whose
+ * concatenation is equivalent to x.
+ */
+ static std::vector<Node> getChars(TNode x);
+
/** Return true if x is empty */
static bool isEmpty(TNode x);
diff --git a/src/theory/theory.h b/src/theory/theory.h
index d6b02e070..63ca46b41 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -42,6 +42,7 @@
#include "theory/logic_info.h"
#include "theory/output_channel.h"
#include "theory/theory_id.h"
+#include "theory/theory_rewriter.h"
#include "theory/valuation.h"
#include "util/statistics_registry.h"
@@ -317,6 +318,11 @@ public:
virtual ~Theory();
/**
+ * Creates a new theory rewriter for the theory.
+ */
+ virtual std::unique_ptr<TheoryRewriter> mkTheoryRewriter() = 0;
+
+ /**
* Subclasses of Theory may add additional efforts. DO NOT CHECK
* equality with one of these values (e.g. if STANDARD xxx) but
* rather use range checks (or use the helper functions below).
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 32a80a418..2c27c6054 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -266,7 +266,6 @@ void TheoryEngine::EngineOutputChannel::conflict(TNode conflictNode,
}
void TheoryEngine::finishInit() {
-
//initialize the quantifiers engine, master equality engine, model, model builder
if( d_logicInfo.isQuantified() ) {
// initialize the quantifiers engine
@@ -350,7 +349,6 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_factsAsserted(context, false),
d_preRegistrationVisitor(this, context),
d_sharedTermsVisitor(d_sharedTerms),
- d_theoryAlternatives(),
d_attr_handle(),
d_arithSubstitutionsAdded("theory::arith::zzz::arith::substitutions", 0)
{
@@ -2374,18 +2372,6 @@ void TheoryEngine::spendResource(ResourceManager::Resource r)
d_resourceManager->spendResource(r);
}
-void TheoryEngine::enableTheoryAlternative(const std::string& name){
- Debug("TheoryEngine::enableTheoryAlternative")
- << "TheoryEngine::enableTheoryAlternative(" << name << ")" << std::endl;
-
- d_theoryAlternatives.insert(name);
-}
-
-bool TheoryEngine::useTheoryAlternative(const std::string& name) {
- return d_theoryAlternatives.find(name) != d_theoryAlternatives.end();
-}
-
-
TheoryEngine::Statistics::Statistics(theory::TheoryId theory):
conflicts(getStatsPrefix(theory) + "::conflicts", 0),
propagations(getStatsPrefix(theory) + "::propagations", 0),
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index c1e1e4cac..dec654e76 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -494,6 +494,8 @@ class TheoryEngine {
*d_theoryOut[theoryId],
theory::Valuation(this),
d_logicInfo);
+ theory::Rewriter::registerTheoryRewriter(
+ theoryId, d_theoryTable[theoryId]->mkTheoryRewriter());
}
void setPropEngine(prop::PropEngine* propEngine)
@@ -895,14 +897,7 @@ public:
/** Prints the assertions to the debug stream */
void printAssertions(const char* tag);
- /** Theory alternative is in use. */
- bool useTheoryAlternative(const std::string& name);
-
- /** Enables using a theory alternative by name. */
- void enableTheoryAlternative(const std::string& name);
-
private:
- std::set< std::string > d_theoryAlternatives;
std::map< std::string, std::vector< theory::Theory* > > d_attr_handle;
diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp
index 7bfb0e8f3..dae7261e5 100644
--- a/src/theory/theory_model.cpp
+++ b/src/theory/theory_model.cpp
@@ -147,7 +147,7 @@ Node TheoryModel::getValue(TNode n) const
Node nn = d_substitutions.apply(n);
Debug("model-getvalue-debug") << "[model-getvalue] getValue : substitute " << n << " to " << nn << std::endl;
//get value in model
- nn = getModelValue(nn, false);
+ nn = getModelValue(nn);
if (nn.isNull()) return nn;
if(options::condenseFunctionValues() || nn.getKind() != kind::LAMBDA) {
//normalize
@@ -193,7 +193,7 @@ Cardinality TheoryModel::getCardinality( Type t ) const{
}
}
-Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
+Node TheoryModel::getModelValue(TNode n) const
{
std::unordered_map<Node, Node, NodeHashFunction>::iterator it = d_modelCache.find(n);
if (it != d_modelCache.end()) {
@@ -220,7 +220,7 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
std::vector<Node> children;
if (n.getKind() == APPLY_UF)
{
- Node op = getModelValue(n.getOperator(), hasBoundVars);
+ Node op = getModelValue(n.getOperator());
Debug("model-getvalue-debug") << " operator : " << op << std::endl;
children.push_back(op);
}
@@ -231,7 +231,7 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
// evaluate the children
for (unsigned i = 0, nchild = n.getNumChildren(); i < nchild; ++i)
{
- ret = getModelValue(n[i], hasBoundVars);
+ ret = getModelValue(n[i]);
Debug("model-getvalue-debug")
<< " " << n << "[" << i << "] is " << ret << std::endl;
children.push_back(ret);
diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h
index d2ce63ac5..d984fbc6b 100644
--- a/src/theory/theory_model.h
+++ b/src/theory/theory_model.h
@@ -390,9 +390,8 @@ public:
/** Get model value function.
*
* This function is a helper function for getValue.
- * hasBoundVars is whether n may contain bound variables
*/
- Node getModelValue(TNode n, bool hasBoundVars = false) const;
+ Node getModelValue(TNode n) const;
/** add term internal
*
* This will do any model-specific processing necessary for n,
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 3b42fa6a1..1ea5449b7 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -66,6 +66,11 @@ TheoryUF::TheoryUF(context::Context* c,
TheoryUF::~TheoryUF() {
}
+std::unique_ptr<TheoryRewriter> TheoryUF::mkTheoryRewriter()
+{
+ return std::unique_ptr<TheoryRewriter>(new TheoryUfRewriter());
+}
+
void TheoryUF::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index 93a709fe5..623c5c64b 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -188,6 +188,8 @@ private:
~TheoryUF();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override;
+
void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
void finishInit() override;
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 75597edac..eba5fb8c9 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -25,12 +25,12 @@ libcvc4_add_sources(
proof.h
random.cpp
random.h
- regexp.cpp
- regexp.h
resource_manager.cpp
resource_manager.h
result.cpp
result.h
+ regexp.cpp
+ regexp.h
safe_print.cpp
safe_print.h
sampler.cpp
@@ -43,6 +43,8 @@ libcvc4_add_sources(
statistics.h
statistics_registry.cpp
statistics_registry.h
+ string.cpp
+ string.h
tuple.h
unsafe_interrupt_exception.h
utility.cpp
diff --git a/src/util/regexp.cpp b/src/util/regexp.cpp
index 00066edb6..7051b251f 100644
--- a/src/util/regexp.cpp
+++ b/src/util/regexp.cpp
@@ -2,514 +2,59 @@
/*! \file regexp.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Tianyi Liang, Andrew Reynolds
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
** in the top-level source directory) and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** \brief Implementation of data structures for regular expression operators.
**/
#include "util/regexp.h"
-#include <algorithm>
-#include <climits>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-
-#include "base/check.h"
-#include "base/exception.h"
-
-using namespace std;
+#include <ostream>
namespace CVC4 {
-static_assert(UCHAR_MAX == 255, "Unsigned char is assumed to have 256 values.");
-
-unsigned String::convertCharToUnsignedInt(unsigned char c)
-{
- return convertCodeToUnsignedInt(static_cast<unsigned>(c));
-}
-unsigned char String::convertUnsignedIntToChar(unsigned i)
-{
- Assert(i < num_codes());
- return static_cast<unsigned char>(convertUnsignedIntToCode(i));
-}
-bool String::isPrintable(unsigned i)
+RegExpRepeat::RegExpRepeat(uint32_t repeatAmount) : d_repeatAmount(repeatAmount)
{
- Assert(i < num_codes());
- unsigned char c = convertUnsignedIntToChar(i);
- return (c >= ' ' && c <= '~');
-}
-unsigned String::convertCodeToUnsignedInt(unsigned c)
-{
- Assert(c < num_codes());
- return (c < start_code() ? c + num_codes() : c) - start_code();
-}
-unsigned String::convertUnsignedIntToCode(unsigned i)
-{
- Assert(i < num_codes());
- return (i + start_code()) % num_codes();
}
-String::String(const std::vector<unsigned> &s) : d_str(s)
+bool RegExpRepeat::operator==(const RegExpRepeat& r) const
{
-#ifdef CVC4_ASSERTIONS
- for (unsigned u : d_str)
- {
- Assert(convertUnsignedIntToCode(u) < num_codes());
- }
-#endif
-}
-
-int String::cmp(const String &y) const {
- if (size() != y.size()) {
- return size() < y.size() ? -1 : 1;
- }
- for (unsigned int i = 0; i < size(); ++i) {
- if (d_str[i] != y.d_str[i]) {
- unsigned cp = convertUnsignedIntToCode(d_str[i]);
- unsigned cpy = convertUnsignedIntToCode(y.d_str[i]);
- return cp < cpy ? -1 : 1;
- }
- }
- return 0;
-}
-
-String String::concat(const String &other) const {
- std::vector<unsigned int> ret_vec(d_str);
- ret_vec.insert(ret_vec.end(), other.d_str.begin(), other.d_str.end());
- return String(ret_vec);
+ return d_repeatAmount == r.d_repeatAmount;
}
-bool String::strncmp(const String& y, std::size_t n) const
+RegExpLoop::RegExpLoop(uint32_t l, uint32_t h)
+ : d_loopMinOcc(l), d_loopMaxOcc(h)
{
- std::size_t b = (size() >= y.size()) ? size() : y.size();
- std::size_t s = (size() <= y.size()) ? size() : y.size();
- if (n > s) {
- if (b == s) {
- n = s;
- } else {
- return false;
- }
- }
- for (std::size_t i = 0; i < n; ++i) {
- if (d_str[i] != y.d_str[i]) return false;
- }
- return true;
}
-bool String::rstrncmp(const String& y, std::size_t n) const
+bool RegExpLoop::operator==(const RegExpLoop& r) const
{
- std::size_t b = (size() >= y.size()) ? size() : y.size();
- std::size_t s = (size() <= y.size()) ? size() : y.size();
- if (n > s) {
- if (b == s) {
- n = s;
- } else {
- return false;
- }
- }
- for (std::size_t i = 0; i < n; ++i) {
- if (d_str[size() - i - 1] != y.d_str[y.size() - i - 1]) return false;
- }
- return true;
-}
-
-std::vector<unsigned> String::toInternal(const std::string &s,
- bool useEscSequences) {
- std::vector<unsigned> str;
- unsigned i = 0;
- while (i < s.size()) {
- if (s[i] == '\\' && useEscSequences) {
- i++;
- if (i < s.size()) {
- switch (s[i]) {
- case 'n': {
- str.push_back(convertCharToUnsignedInt('\n'));
- i++;
- } break;
- case 't': {
- str.push_back(convertCharToUnsignedInt('\t'));
- i++;
- } break;
- case 'v': {
- str.push_back(convertCharToUnsignedInt('\v'));
- i++;
- } break;
- case 'b': {
- str.push_back(convertCharToUnsignedInt('\b'));
- i++;
- } break;
- case 'r': {
- str.push_back(convertCharToUnsignedInt('\r'));
- i++;
- } break;
- case 'f': {
- str.push_back(convertCharToUnsignedInt('\f'));
- i++;
- } break;
- case 'a': {
- str.push_back(convertCharToUnsignedInt('\a'));
- i++;
- } break;
- case '\\': {
- str.push_back(convertCharToUnsignedInt('\\'));
- i++;
- } break;
- case 'x': {
- if (i + 2 < s.size()) {
- if (isxdigit(s[i + 1]) && isxdigit(s[i + 2])) {
- str.push_back(convertCharToUnsignedInt(hexToDec(s[i + 1]) * 16 +
- hexToDec(s[i + 2])));
- i += 3;
- } else {
- throw CVC4::Exception("Illegal String Literal: \"" + s + "\"");
- }
- } else {
- throw CVC4::Exception("Illegal String Literal: \"" + s +
- "\", must have two digits after \\x");
- }
- } break;
- default: {
- if (isdigit(s[i])) {
- // octal escape sequences TODO : revisit (issue #1251).
- int num = (int)s[i] - (int)'0';
- bool flag = num < 4;
- if (i + 1 < s.size() && num < 8 && isdigit(s[i + 1]) &&
- s[i + 1] < '8') {
- num = num * 8 + (int)s[i + 1] - (int)'0';
- if (flag && i + 2 < s.size() && isdigit(s[i + 2]) &&
- s[i + 2] < '8') {
- num = num * 8 + (int)s[i + 2] - (int)'0';
- str.push_back(convertCharToUnsignedInt((unsigned char)num));
- i += 3;
- } else {
- str.push_back(convertCharToUnsignedInt((unsigned char)num));
- i += 2;
- }
- } else {
- str.push_back(convertCharToUnsignedInt((unsigned char)num));
- i++;
- }
- } else if ((unsigned)s[i] > 127) {
- throw CVC4::Exception("Illegal String Literal: \"" + s +
- "\", must use escaped sequence");
- } else {
- str.push_back(convertCharToUnsignedInt(s[i]));
- i++;
- }
- }
- }
- } else {
- throw CVC4::Exception("should be handled by lexer: \"" + s + "\"");
- // str.push_back( convertCharToUnsignedInt('\\') );
- }
- } else if ((unsigned)s[i] > 127 && useEscSequences) {
- throw CVC4::Exception("Illegal String Literal: \"" + s +
- "\", must use escaped sequence");
- } else {
- str.push_back(convertCharToUnsignedInt(s[i]));
- i++;
- }
- }
-#ifdef CVC4_ASSERTIONS
- for (unsigned u : str)
- {
- Assert(convertUnsignedIntToCode(u) < num_codes());
- }
-#endif
- return str;
+ return d_loopMinOcc == r.d_loopMinOcc && d_loopMaxOcc == r.d_loopMaxOcc;
}
-unsigned String::front() const
+size_t RegExpRepeatHashFunction::operator()(const RegExpRepeat& r) const
{
- Assert(!d_str.empty());
- return d_str.front();
+ return r.d_repeatAmount;
}
-unsigned String::back() const
+size_t RegExpLoopHashFunction::operator()(const RegExpLoop& r) const
{
- Assert(!d_str.empty());
- return d_str.back();
-}
-
-std::size_t String::overlap(const String &y) const {
- std::size_t i = size() < y.size() ? size() : y.size();
- for (; i > 0; i--) {
- String s = suffix(i);
- String p = y.prefix(i);
- if (s == p) {
- return i;
- }
- }
- return i;
-}
-
-std::size_t String::roverlap(const String &y) const {
- std::size_t i = size() < y.size() ? size() : y.size();
- for (; i > 0; i--) {
- String s = prefix(i);
- String p = y.suffix(i);
- if (s == p) {
- return i;
- }
- }
- return i;
+ return r.d_loopMinOcc + r.d_loopMaxOcc;
}
-std::string String::toString(bool useEscSequences) const {
- std::string str;
- for (unsigned int i = 0; i < size(); ++i) {
- unsigned char c = convertUnsignedIntToChar(d_str[i]);
- if (!useEscSequences) {
- str += c;
- } else if (isprint(c)) {
- if (c == '\\') {
- str += "\\\\";
- }
- // else if(c == '\"') {
- // str += "\\\"";
- //}
- else {
- str += c;
- }
- } else {
- std::string s;
- switch (c) {
- case '\a':
- s = "\\a";
- break;
- case '\b':
- s = "\\b";
- break;
- case '\t':
- s = "\\t";
- break;
- case '\r':
- s = "\\r";
- break;
- case '\v':
- s = "\\v";
- break;
- case '\f':
- s = "\\f";
- break;
- case '\n':
- s = "\\n";
- break;
- case '\e':
- s = "\\e";
- break;
- default: {
- std::stringstream ss;
- ss << std::setfill('0') << std::setw(2) << std::hex << ((int)c);
- std::string t = ss.str();
- t = t.substr(t.size() - 2, 2);
- s = "\\x" + t;
- // std::string s2 = static_cast<std::ostringstream*>(
- // &(std::ostringstream() << (int)c) )->str();
- }
- }
- str += s;
- }
- }
- return str;
-}
-
-bool String::isLeq(const String &y) const
+std::ostream& operator<<(std::ostream& os, const RegExpRepeat& r)
{
- for (unsigned i = 0; i < size(); ++i)
- {
- if (i >= y.size())
- {
- return false;
- }
- unsigned ci = convertUnsignedIntToCode(d_str[i]);
- unsigned cyi = convertUnsignedIntToCode(y.d_str[i]);
- if (ci > cyi)
- {
- return false;
- }
- if (ci < cyi)
- {
- return true;
- }
- }
- return true;
-}
-
-bool String::isRepeated() const {
- if (size() > 1) {
- unsigned int f = d_str[0];
- for (unsigned i = 1; i < size(); ++i) {
- if (f != d_str[i]) return false;
- }
- }
- return true;
+ return os << r.d_repeatAmount;
}
-bool String::tailcmp(const String &y, int &c) const {
- int id_x = size() - 1;
- int id_y = y.size() - 1;
- while (id_x >= 0 && id_y >= 0) {
- if (d_str[id_x] != y.d_str[id_y]) {
- c = id_x;
- return false;
- }
- --id_x;
- --id_y;
- }
- c = id_x == -1 ? (-(id_y + 1)) : (id_x + 1);
- return true;
-}
-
-std::size_t String::find(const String &y, const std::size_t start) const {
- if (size() < y.size() + start) return std::string::npos;
- if (y.empty()) return start;
- if (empty()) return std::string::npos;
-
- std::vector<unsigned>::const_iterator itr = std::search(
- d_str.begin() + start, d_str.end(), y.d_str.begin(), y.d_str.end());
- if (itr != d_str.end()) {
- return itr - d_str.begin();
- }
- return std::string::npos;
-}
-
-std::size_t String::rfind(const String &y, const std::size_t start) const {
- if (size() < y.size() + start) return std::string::npos;
- if (y.empty()) return start;
- if (empty()) return std::string::npos;
-
- std::vector<unsigned>::const_reverse_iterator itr = std::search(
- d_str.rbegin() + start, d_str.rend(), y.d_str.rbegin(), y.d_str.rend());
- if (itr != d_str.rend()) {
- return itr - d_str.rbegin();
- }
- return std::string::npos;
-}
-
-bool String::hasPrefix(const String& y) const
+std::ostream& operator<<(std::ostream& os, const RegExpLoop& r)
{
- size_t s = size();
- size_t ys = y.size();
- if (ys > s)
- {
- return false;
- }
- for (size_t i = 0; i < ys; i++)
- {
- if (d_str[i] != y.d_str[i])
- {
- return false;
- }
- }
- return true;
-}
-
-bool String::hasSuffix(const String& y) const
-{
- size_t s = size();
- size_t ys = y.size();
- if (ys > s)
- {
- return false;
- }
- size_t idiff = s - ys;
- for (size_t i = 0; i < ys; i++)
- {
- if (d_str[i + idiff] != y.d_str[i])
- {
- return false;
- }
- }
- return true;
-}
-
-String String::replace(const String &s, const String &t) const {
- std::size_t ret = find(s);
- if (ret != std::string::npos) {
- std::vector<unsigned int> vec;
- vec.insert(vec.begin(), d_str.begin(), d_str.begin() + ret);
- vec.insert(vec.end(), t.d_str.begin(), t.d_str.end());
- vec.insert(vec.end(), d_str.begin() + ret + s.size(), d_str.end());
- return String(vec);
- } else {
- return *this;
- }
-}
-
-String String::substr(std::size_t i) const {
- Assert(i <= size());
- std::vector<unsigned int> ret_vec;
- std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
- ret_vec.insert(ret_vec.end(), itr, d_str.end());
- return String(ret_vec);
-}
-
-String String::substr(std::size_t i, std::size_t j) const {
- Assert(i + j <= size());
- std::vector<unsigned int> ret_vec;
- std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
- ret_vec.insert(ret_vec.end(), itr, itr + j);
- return String(ret_vec);
-}
-
-bool String::noOverlapWith(const String& y) const
-{
- return y.find(*this) == std::string::npos
- && this->find(y) == std::string::npos && this->overlap(y) == 0
- && y.overlap(*this) == 0;
-}
-
-bool String::isNumber() const {
- if (d_str.empty()) {
- return false;
- }
- for (unsigned character : d_str) {
- if (!isDigit(character))
- {
- return false;
- }
- }
- return true;
-}
-
-bool String::isDigit(unsigned character)
-{
- unsigned char c = convertUnsignedIntToChar(character);
- return c >= '0' && c <= '9';
-}
-
-size_t String::maxSize() { return std::numeric_limits<uint32_t>::max(); }
-
-Rational String::toNumber() const
-{
- // when smt2 standard for strings is set, this may change, based on the
- // semantics of str.from.int for leading zeros
- return Rational(toString());
-}
-
-unsigned char String::hexToDec(unsigned char c) {
- if (c >= '0' && c <= '9') {
- return c - '0';
- } else if (c >= 'a' && c <= 'f') {
- return c - 'a' + 10;
- } else {
- Assert(c >= 'A' && c <= 'F');
- return c - 'A' + 10;
- }
-}
-
-std::ostream &operator<<(std::ostream &os, const String &s) {
- return os << "\"" << s.toString(true) << "\"";
+ return os << "[" << r.d_loopMinOcc << ".." << r.d_loopMaxOcc << "]";
}
} // namespace CVC4
diff --git a/src/util/regexp.h b/src/util/regexp.h
index 731736f72..aaba9e4db 100644
--- a/src/util/regexp.h
+++ b/src/util/regexp.h
@@ -2,269 +2,74 @@
/*! \file regexp.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Tianyi Liang
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
** in the top-level source directory) and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** \brief Data structures for regular expression operators.
**/
#include "cvc4_public.h"
-#ifndef CVC4__REGEXP_H
-#define CVC4__REGEXP_H
+#ifndef CVC4__UTIL__REGEXP_H
+#define CVC4__UTIL__REGEXP_H
-#include <cstddef>
-#include <functional>
-#include <ostream>
-#include <string>
-#include <vector>
-#include "util/rational.h"
+#include <cstdint>
+#include <iosfwd>
namespace CVC4 {
-/** The CVC4 string class
- *
- * This data structure is the domain of values for the string type. It can also
- * be used as a generic utility for representing strings.
- */
-class CVC4_PUBLIC String {
- public:
- /**
- * The start ASCII code. In our string representation below, we represent
- * characters using a vector d_str of unsigned integers. We refer to this as
- * the "internal representation" for the string.
- *
- * We make unsigned integer 0 correspond to the 65th character ("A") in the
- * ASCII alphabet to make models intuitive. In particular, say if we have
- * a set of string variables that are distinct but otherwise unconstrained,
- * then the model may assign them "A", "B", "C", ...
- */
- static inline unsigned start_code() { return 65; }
- /**
- * This is the cardinality of the alphabet that is representable by this
- * class. Notice that this must be greater than or equal to the cardinality
- * of the alphabet that the string theory reasons about.
- *
- * This must be strictly less than std::numeric_limits<unsigned>::max().
- */
- static inline unsigned num_codes() { return 256; }
- /**
- * Convert unsigned char to the unsigned used in the internal representation
- * in d_str below.
- */
- static unsigned convertCharToUnsignedInt(unsigned char c);
- /** Convert the internal unsigned to a unsigned char. */
- static unsigned char convertUnsignedIntToChar(unsigned i);
- /** Does the internal unsigned correspond to a printable character? */
- static bool isPrintable(unsigned i);
- /** get the internal unsigned for ASCII code c. */
- static unsigned convertCodeToUnsignedInt(unsigned c);
- /** get the ASCII code number that internal unsigned i corresponds to. */
- static unsigned convertUnsignedIntToCode(unsigned i);
-
- /** constructors for String
- *
- * Internally, a CVC4::String is represented by a vector of unsigned
- * integers (d_str), where the correspondence between C++ characters
- * to and from unsigned integers is determined by
- * by convertCharToUnsignedInt and convertUnsignedIntToChar.
- *
- * If useEscSequences is true, then the escape sequences in the input
- * are converted to the corresponding character. This constructor may
- * throw an exception if the input contains unrecognized escape sequences.
- * Currently supported escape sequences are \n, \t, \v, \b, \r, \f, \a, \\,
- * \x[N] where N is a hexidecimal, and octal escape sequences of the
- * form \[c1]([c2]([c3])?)? where c1, c2, c3 are digits from 0 to 7.
- *
- * If useEscSequences is false, then the characters of the constructed
- * CVC4::String correspond one-to-one with the input string.
- */
- String() = default;
- explicit String(const std::string& s, bool useEscSequences = false)
- : d_str(toInternal(s, useEscSequences)) {}
- explicit String(const char* s, bool useEscSequences = false)
- : d_str(toInternal(std::string(s), useEscSequences)) {}
- explicit String(const std::vector<unsigned>& s);
-
- String& operator=(const String& y) {
- if (this != &y) {
- d_str = y.d_str;
- }
- return *this;
- }
-
- String concat(const String& other) const;
-
- bool operator==(const String& y) const { return cmp(y) == 0; }
- bool operator!=(const String& y) const { return cmp(y) != 0; }
- bool operator<(const String& y) const { return cmp(y) < 0; }
- bool operator>(const String& y) const { return cmp(y) > 0; }
- bool operator<=(const String& y) const { return cmp(y) <= 0; }
- bool operator>=(const String& y) const { return cmp(y) >= 0; }
-
- /**
- * Returns true if this string is equal to y for their first n characters.
- * If n is larger than the length of this string or y, this method returns
- * true if and only if this string is equal to y.
- */
- bool strncmp(const String& y, std::size_t n) const;
- /**
- * Returns true if this string is equal to y for their last n characters.
- * Similar to strncmp, if n is larger than the length of this string or y,
- * this method returns true if and only if this string is equal to y.
- */
- bool rstrncmp(const String& y, std::size_t n) const;
+struct CVC4_PUBLIC RegExpRepeat
+{
+ RegExpRepeat(uint32_t repeatAmount);
- /* toString
- * Converts this string to a std::string.
- *
- * If useEscSequences is true, then unprintable characters
- * are converted to escape sequences. The escape sequences
- * \n, \t, \v, \b, \r, \f, \a, \\ are printed in this way.
- * For all other unprintable characters, we print \x[N] where
- * [N] is the 2 digit hexidecimal corresponding to value of
- * the character.
- *
- * If useEscSequences is false, the returned std::string's characters
- * map one-to-one with the characters in this string.
- * Notice that for all std::string s, we have that
- * CVC4::String( s ).toString() = s.
- */
- std::string toString(bool useEscSequences = false) const;
- /** is this the empty string? */
- bool empty() const { return d_str.empty(); }
- /** is this the empty string? */
- bool isEmptyString() const { return empty(); }
- /** is less than or equal to string y */
- bool isLeq(const String& y) const;
- /** Return the length of the string */
- std::size_t size() const { return d_str.size(); }
+ bool operator==(const RegExpRepeat& r) const;
+ /** The amount of repetitions of the regular expression */
+ uint32_t d_repeatAmount;
+};
- bool isRepeated() const;
- bool tailcmp(const String& y, int& c) const;
+struct CVC4_PUBLIC RegExpLoop
+{
+ RegExpLoop(uint32_t l, uint32_t h);
- /**
- * Return the first position y occurs in this string, or std::string::npos
- * otherwise.
- */
- std::size_t find(const String& y, const std::size_t start = 0) const;
- /**
- * Return the first position y occurs in this string searching from the end,
- * or std::string::npos otherwise.
- */
- std::size_t rfind(const String& y, const std::size_t start = 0) const;
- /** Returns true if y is a prefix of this */
- bool hasPrefix(const String& y) const;
- /** Returns true if y is a suffix of this */
- bool hasSuffix(const String& y) const;
- /** Replace the first occurrence of s in this string with t */
- String replace(const String& s, const String& t) const;
- /** Return the substring of this string starting at index i */
- String substr(std::size_t i) const;
- /** Return the substring of this string starting at index i with size at most
- * j */
- String substr(std::size_t i, std::size_t j) const;
- /** Return the prefix of this string of size at most i */
- String prefix(std::size_t i) const { return substr(0, i); }
- /** Return the suffix of this string of size at most i */
- String suffix(std::size_t i) const { return substr(size() - i, i); }
+ bool operator==(const RegExpLoop& r) const;
+ /** The minimum number of repetitions of the regular expression */
+ uint32_t d_loopMinOcc;
+ /** The maximum number of repetitions of the regular expression */
+ uint32_t d_loopMaxOcc;
+};
- /**
- * Checks if there is any overlap between this string and another string. This
- * corresponds to checking whether one string contains the other and whether a
- * substring of one is a prefix of the other and vice-versa.
- *
- * @param y The other string
- * @return True if there is an overlap, false otherwise
- */
- bool noOverlapWith(const String& y) const;
+/* -----------------------------------------------------------------------
+ ** Hash Function structs
+ * ----------------------------------------------------------------------- */
- /** string overlap
- *
- * if overlap returns m>0,
- * then the maximal suffix of this string that is a prefix of y is of length m.
- *
- * For example, if x is "abcdef", then:
- * x.overlap("defg") = 3
- * x.overlap("ab") = 0
- * x.overlap("d") = 0
- * x.overlap("bcdefdef") = 5
- */
- std::size_t overlap(const String& y) const;
- /** string reverse overlap
- *
- * if roverlap returns m>0,
- * then the maximal prefix of this string that is a suffix of y is of length m.
- *
- * For example, if x is "abcdef", then:
- * x.roverlap("aaabc") = 3
- * x.roverlap("def") = 0
- * x.roverlap("d") = 0
- * x.roverlap("defabcde") = 5
- *
- * Notice that x.overlap(y) = y.roverlap(x)
- */
- std::size_t roverlap(const String& y) const;
-
- /**
- * Returns true if this string corresponds in text to a number, for example
- * this returns true for strings "7", "12", "004", "0" and false for strings
- * "abc", "4a", "-4", "".
- */
- bool isNumber() const;
- /** Returns the corresponding rational for the text of this string. */
- Rational toNumber() const;
- /** get the internal unsigned representation of this string */
- const std::vector<unsigned>& getVec() const { return d_str; }
- /** get the internal unsigned value of the first character in this string */
- unsigned front() const;
- /** get the internal unsigned value of the last character in this string */
- unsigned back() const;
- /** is the unsigned a digit?
- * The input should be the same type as the element type of d_str
- */
- static bool isDigit(unsigned character);
-
- /**
- * Returns the maximum length of string representable by this class.
- * Corresponds to the maximum size of d_str.
- */
- static size_t maxSize();
- private:
- // guarded
- static unsigned char hexToDec(unsigned char c);
-
- static std::vector<unsigned> toInternal(const std::string& s,
- bool useEscSequences = true);
-
- /**
- * Returns a negative number if *this < y, 0 if *this and y are equal and a
- * positive number if *this > y.
- */
- int cmp(const String& y) const;
-
- std::vector<unsigned> d_str;
-}; /* class String */
+/*
+ * Hash function for the RegExpRepeat constants.
+ */
+struct CVC4_PUBLIC RegExpRepeatHashFunction
+{
+ size_t operator()(const RegExpRepeat& r) const;
+};
-namespace strings {
+/**
+ * Hash function for the RegExpLoop objects.
+ */
+struct CVC4_PUBLIC RegExpLoopHashFunction
+{
+ size_t operator()(const RegExpLoop& r) const;
+};
-struct CVC4_PUBLIC StringHashFunction {
- size_t operator()(const ::CVC4::String& s) const {
- return std::hash<std::string>()(s.toString());
- }
-}; /* struct StringHashFunction */
+/* -----------------------------------------------------------------------
+ ** Output stream
+ * ----------------------------------------------------------------------- */
-} // namespace strings
+std::ostream& operator<<(std::ostream& os, const RegExpRepeat& bv) CVC4_PUBLIC;
-std::ostream& operator<<(std::ostream& os, const String& s) CVC4_PUBLIC;
+std::ostream& operator<<(std::ostream& os, const RegExpLoop& bv) CVC4_PUBLIC;
} // namespace CVC4
-#endif /* CVC4__REGEXP_H */
+#endif /* CVC4__UTIL__REGEXP_H */
diff --git a/src/util/regexp.i b/src/util/regexp.i
index afc51abd7..775e778f7 100644
--- a/src/util/regexp.i
+++ b/src/util/regexp.i
@@ -2,24 +2,11 @@
#include "util/regexp.h"
%}
-%rename(CVC4String) String;
-%rename(CVC4StringHashFunction) CVC4::strings::StringHashFunction;
+%rename(equals) CVC4::RegExpRepeat::operator==(const RegExpRepeat&) const;
-%ignore CVC4::String::String(const std::string&);
+%rename(equals) CVC4::RegExpLoop::operator==(const RegExpLoop&) const;
-%rename(assign) CVC4::String::operator=(const String&);
-%rename(getChar) CVC4::String::operator[](const unsigned int) const;
-%rename(equals) CVC4::String::operator==(const String&) const;
-%ignore CVC4::String::operator!=(const String&) const;
-%rename(less) CVC4::String::operator<(const String&) const;
-%rename(lessEqual) CVC4::String::operator<=(const String&) const;
-%rename(greater) CVC4::String::operator>(const String&) const;
-%rename(greaterEqual) CVC4::String::operator>=(const String&) const;
+%ignore CVC4::operator<<(std::ostream&, const RegExpRepeat&);
+%ignore CVC4::operator<<(std::ostream&, const RegExpLoop&);
-%rename(apply) CVC4::strings::StringHashFunction::operator()(const ::CVC4::String&) const;
-
-%ignore CVC4::operator<<(std::ostream&, const String&);
-
-%apply int &OUTPUT { int &c };
%include "util/regexp.h"
-%clear int &c;
diff --git a/src/util/result.cpp b/src/util/result.cpp
index 433dcbf29..916e16b4f 100644
--- a/src/util/result.cpp
+++ b/src/util/result.cpp
@@ -29,59 +29,68 @@ namespace CVC4 {
Result::Result()
: d_sat(SAT_UNKNOWN),
- d_validity(VALIDITY_UNKNOWN),
+ d_entailment(ENTAILMENT_UNKNOWN),
d_which(TYPE_NONE),
d_unknownExplanation(UNKNOWN_REASON),
- d_inputName("") {}
+ d_inputName("")
+{
+}
Result::Result(enum Sat s, std::string inputName)
: d_sat(s),
- d_validity(VALIDITY_UNKNOWN),
+ d_entailment(ENTAILMENT_UNKNOWN),
d_which(TYPE_SAT),
d_unknownExplanation(UNKNOWN_REASON),
- d_inputName(inputName) {
+ d_inputName(inputName)
+{
PrettyCheckArgument(s != SAT_UNKNOWN,
"Must provide a reason for satisfiability being unknown");
}
-Result::Result(enum Validity v, std::string inputName)
+Result::Result(enum Entailment e, std::string inputName)
: d_sat(SAT_UNKNOWN),
- d_validity(v),
- d_which(TYPE_VALIDITY),
+ d_entailment(e),
+ d_which(TYPE_ENTAILMENT),
d_unknownExplanation(UNKNOWN_REASON),
- d_inputName(inputName) {
- PrettyCheckArgument(v != VALIDITY_UNKNOWN,
- "Must provide a reason for validity being unknown");
+ d_inputName(inputName)
+{
+ PrettyCheckArgument(e != ENTAILMENT_UNKNOWN,
+ "Must provide a reason for entailment being unknown");
}
-Result::Result(enum Sat s, enum UnknownExplanation unknownExplanation,
+Result::Result(enum Sat s,
+ enum UnknownExplanation unknownExplanation,
std::string inputName)
: d_sat(s),
- d_validity(VALIDITY_UNKNOWN),
+ d_entailment(ENTAILMENT_UNKNOWN),
d_which(TYPE_SAT),
d_unknownExplanation(unknownExplanation),
- d_inputName(inputName) {
+ d_inputName(inputName)
+{
PrettyCheckArgument(s == SAT_UNKNOWN,
"improper use of unknown-result constructor");
}
-Result::Result(enum Validity v, enum UnknownExplanation unknownExplanation,
+Result::Result(enum Entailment e,
+ enum UnknownExplanation unknownExplanation,
std::string inputName)
: d_sat(SAT_UNKNOWN),
- d_validity(v),
- d_which(TYPE_VALIDITY),
+ d_entailment(e),
+ d_which(TYPE_ENTAILMENT),
d_unknownExplanation(unknownExplanation),
- d_inputName(inputName) {
- PrettyCheckArgument(v == VALIDITY_UNKNOWN,
+ d_inputName(inputName)
+{
+ PrettyCheckArgument(e == ENTAILMENT_UNKNOWN,
"improper use of unknown-result constructor");
}
Result::Result(const std::string& instr, std::string inputName)
: d_sat(SAT_UNKNOWN),
- d_validity(VALIDITY_UNKNOWN),
+ d_entailment(ENTAILMENT_UNKNOWN),
d_which(TYPE_NONE),
d_unknownExplanation(UNKNOWN_REASON),
- d_inputName(inputName) {
+ d_inputName(inputName)
+{
string s = instr;
transform(s.begin(), s.end(), s.begin(), ::tolower);
if (s == "sat" || s == "satisfiable") {
@@ -90,38 +99,56 @@ Result::Result(const std::string& instr, std::string inputName)
} else if (s == "unsat" || s == "unsatisfiable") {
d_which = TYPE_SAT;
d_sat = UNSAT;
- } else if (s == "valid") {
- d_which = TYPE_VALIDITY;
- d_validity = VALID;
- } else if (s == "invalid") {
- d_which = TYPE_VALIDITY;
- d_validity = INVALID;
- } else if (s == "incomplete") {
+ }
+ else if (s == "entailed")
+ {
+ d_which = TYPE_ENTAILMENT;
+ d_entailment = ENTAILED;
+ }
+ else if (s == "not_entailed")
+ {
+ d_which = TYPE_ENTAILMENT;
+ d_entailment = NOT_ENTAILED;
+ }
+ else if (s == "incomplete")
+ {
d_which = TYPE_SAT;
d_sat = SAT_UNKNOWN;
d_unknownExplanation = INCOMPLETE;
- } else if (s == "timeout") {
+ }
+ else if (s == "timeout")
+ {
d_which = TYPE_SAT;
d_sat = SAT_UNKNOWN;
d_unknownExplanation = TIMEOUT;
- } else if (s == "resourceout") {
+ }
+ else if (s == "resourceout")
+ {
d_which = TYPE_SAT;
d_sat = SAT_UNKNOWN;
d_unknownExplanation = RESOURCEOUT;
- } else if (s == "memout") {
+ }
+ else if (s == "memout")
+ {
d_which = TYPE_SAT;
d_sat = SAT_UNKNOWN;
d_unknownExplanation = MEMOUT;
- } else if (s == "interrupted") {
+ }
+ else if (s == "interrupted")
+ {
d_which = TYPE_SAT;
d_sat = SAT_UNKNOWN;
d_unknownExplanation = INTERRUPTED;
- } else if (s.size() >= 7 && s.compare(0, 7, "unknown") == 0) {
+ }
+ else if (s.size() >= 7 && s.compare(0, 7, "unknown") == 0)
+ {
d_which = TYPE_SAT;
d_sat = SAT_UNKNOWN;
- } else {
+ }
+ else
+ {
IllegalArgument(s,
- "expected satisfiability/validity result, "
+ "expected satisfiability/entailment result, "
"instead got `%s'",
s.c_str());
}
@@ -142,37 +169,41 @@ bool Result::operator==(const Result& r) const {
return d_sat == r.d_sat && (d_sat != SAT_UNKNOWN ||
d_unknownExplanation == r.d_unknownExplanation);
}
- if (d_which == TYPE_VALIDITY) {
- return d_validity == r.d_validity &&
- (d_validity != VALIDITY_UNKNOWN ||
- d_unknownExplanation == r.d_unknownExplanation);
+ if (d_which == TYPE_ENTAILMENT)
+ {
+ return d_entailment == r.d_entailment
+ && (d_entailment != ENTAILMENT_UNKNOWN
+ || d_unknownExplanation == r.d_unknownExplanation);
}
return false;
}
bool operator==(enum Result::Sat sr, const Result& r) { return r == sr; }
-bool operator==(enum Result::Validity vr, const Result& r) { return r == vr; }
+bool operator==(enum Result::Entailment e, const Result& r) { return r == e; }
bool operator!=(enum Result::Sat s, const Result& r) { return !(s == r); }
-bool operator!=(enum Result::Validity v, const Result& r) { return !(v == r); }
+bool operator!=(enum Result::Entailment e, const Result& r)
+{
+ return !(e == r);
+}
Result Result::asSatisfiabilityResult() const {
if (d_which == TYPE_SAT) {
return *this;
}
- if (d_which == TYPE_VALIDITY) {
- switch (d_validity) {
- case INVALID:
- return Result(SAT, d_inputName);
+ if (d_which == TYPE_ENTAILMENT)
+ {
+ switch (d_entailment)
+ {
+ case NOT_ENTAILED: return Result(SAT, d_inputName);
- case VALID:
- return Result(UNSAT, d_inputName);
+ case ENTAILED: return Result(UNSAT, d_inputName);
- case VALIDITY_UNKNOWN:
+ case ENTAILMENT_UNKNOWN:
return Result(SAT_UNKNOWN, d_unknownExplanation, d_inputName);
- default: Unhandled() << d_validity;
+ default: Unhandled() << d_entailment;
}
}
@@ -180,28 +211,28 @@ Result Result::asSatisfiabilityResult() const {
return Result(SAT_UNKNOWN, NO_STATUS, d_inputName);
}
-Result Result::asValidityResult() const {
- if (d_which == TYPE_VALIDITY) {
+Result Result::asEntailmentResult() const
+{
+ if (d_which == TYPE_ENTAILMENT)
+ {
return *this;
}
if (d_which == TYPE_SAT) {
switch (d_sat) {
- case SAT:
- return Result(INVALID, d_inputName);
+ case SAT: return Result(NOT_ENTAILED, d_inputName);
- case UNSAT:
- return Result(VALID, d_inputName);
+ case UNSAT: return Result(ENTAILED, d_inputName);
case SAT_UNKNOWN:
- return Result(VALIDITY_UNKNOWN, d_unknownExplanation, d_inputName);
+ return Result(ENTAILMENT_UNKNOWN, d_unknownExplanation, d_inputName);
default: Unhandled() << d_sat;
}
}
// TYPE_NONE
- return Result(VALIDITY_UNKNOWN, NO_STATUS, d_inputName);
+ return Result(ENTAILMENT_UNKNOWN, NO_STATUS, d_inputName);
}
string Result::toString() const {
@@ -226,18 +257,14 @@ ostream& operator<<(ostream& out, enum Result::Sat s) {
return out;
}
-ostream& operator<<(ostream& out, enum Result::Validity v) {
- switch (v) {
- case Result::INVALID:
- out << "INVALID";
- break;
- case Result::VALID:
- out << "VALID";
- break;
- case Result::VALIDITY_UNKNOWN:
- out << "VALIDITY_UNKNOWN";
- break;
- default: Unhandled() << v;
+ostream& operator<<(ostream& out, enum Result::Entailment e)
+{
+ switch (e)
+ {
+ case Result::NOT_ENTAILED: out << "NOT_ENTAILED"; break;
+ case Result::ENTAILED: out << "ENTAILED"; break;
+ case Result::ENTAILMENT_UNKNOWN: out << "ENTAILMENT_UNKNOWN"; break;
+ default: Unhandled() << e;
}
return out;
}
@@ -301,14 +328,11 @@ void Result::toStreamDefault(std::ostream& out) const {
break;
}
} else {
- switch (isValid()) {
- case Result::INVALID:
- out << "invalid";
- break;
- case Result::VALID:
- out << "valid";
- break;
- case Result::VALIDITY_UNKNOWN:
+ switch (isEntailed())
+ {
+ case Result::NOT_ENTAILED: out << "not_entailed"; break;
+ case Result::ENTAILED: out << "entailed"; break;
+ case Result::ENTAILMENT_UNKNOWN:
out << "unknown";
if (whyUnknown() != Result::UNKNOWN_REASON) {
out << " (" << whyUnknown() << ")";
@@ -332,11 +356,17 @@ void Result::toStreamTptp(std::ostream& out) const {
out << "Satisfiable";
} else if (isSat() == Result::UNSAT) {
out << "Unsatisfiable";
- } else if (isValid() == Result::VALID) {
+ }
+ else if (isEntailed() == Result::ENTAILED)
+ {
out << "Theorem";
- } else if (isValid() == Result::INVALID) {
+ }
+ else if (isEntailed() == Result::NOT_ENTAILED)
+ {
out << "CounterSatisfiable";
- } else {
+ }
+ else
+ {
out << "GaveUp";
}
out << " for " << getInputName();
diff --git a/src/util/result.h b/src/util/result.h
index f34a9bb5a..10df05388 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -38,9 +38,19 @@ class CVC4_PUBLIC Result {
public:
enum Sat { UNSAT = 0, SAT = 1, SAT_UNKNOWN = 2 };
- enum Validity { INVALID = 0, VALID = 1, VALIDITY_UNKNOWN = 2 };
+ enum Entailment
+ {
+ NOT_ENTAILED = 0,
+ ENTAILED = 1,
+ ENTAILMENT_UNKNOWN = 2
+ };
- enum Type { TYPE_SAT, TYPE_VALIDITY, TYPE_NONE };
+ enum Type
+ {
+ TYPE_SAT,
+ TYPE_ENTAILMENT,
+ TYPE_NONE
+ };
enum UnknownExplanation {
REQUIRES_FULL_CHECK,
@@ -57,7 +67,7 @@ class CVC4_PUBLIC Result {
private:
enum Sat d_sat;
- enum Validity d_validity;
+ enum Entailment d_entailment;
enum Type d_which;
enum UnknownExplanation d_unknownExplanation;
std::string d_inputName;
@@ -67,12 +77,13 @@ class CVC4_PUBLIC Result {
Result(enum Sat s, std::string inputName = "");
- Result(enum Validity v, std::string inputName = "");
+ Result(enum Entailment v, std::string inputName = "");
Result(enum Sat s, enum UnknownExplanation unknownExplanation,
std::string inputName = "");
- Result(enum Validity v, enum UnknownExplanation unknownExplanation,
+ Result(enum Entailment v,
+ enum UnknownExplanation unknownExplanation,
std::string inputName = "");
Result(const std::string& s, std::string inputName = "");
@@ -84,12 +95,13 @@ class CVC4_PUBLIC Result {
enum Sat isSat() const { return d_which == TYPE_SAT ? d_sat : SAT_UNKNOWN; }
- enum Validity isValid() const {
- return d_which == TYPE_VALIDITY ? d_validity : VALIDITY_UNKNOWN;
+ enum Entailment isEntailed() const
+ {
+ return d_which == TYPE_ENTAILMENT ? d_entailment : ENTAILMENT_UNKNOWN;
}
bool isUnknown() const {
- return isSat() == SAT_UNKNOWN && isValid() == VALIDITY_UNKNOWN;
+ return isSat() == SAT_UNKNOWN && isEntailed() == ENTAILMENT_UNKNOWN;
}
Type getType() const { return d_which; }
@@ -101,7 +113,7 @@ class CVC4_PUBLIC Result {
bool operator==(const Result& r) const;
inline bool operator!=(const Result& r) const;
Result asSatisfiabilityResult() const;
- Result asValidityResult() const;
+ Result asEntailmentResult() const;
std::string toString() const;
@@ -128,7 +140,7 @@ class CVC4_PUBLIC Result {
* Write a Result out to a stream.
*
* The default implementation writes a reasonable string in lowercase
- * for sat, unsat, valid, invalid, or unknown results. This behavior
+ * for sat, unsat, entailed, not entailed, or unknown results. This behavior
* is overridable by each Printer, since sometimes an output language
* has a particular preference for how results should appear.
*/
@@ -139,15 +151,15 @@ inline bool Result::operator!=(const Result& r) const { return !(*this == r); }
std::ostream& operator<<(std::ostream& out, enum Result::Sat s) CVC4_PUBLIC;
std::ostream& operator<<(std::ostream& out,
- enum Result::Validity v) CVC4_PUBLIC;
+ enum Result::Entailment e) CVC4_PUBLIC;
std::ostream& operator<<(std::ostream& out,
enum Result::UnknownExplanation e) CVC4_PUBLIC;
bool operator==(enum Result::Sat s, const Result& r) CVC4_PUBLIC;
-bool operator==(enum Result::Validity v, const Result& r) CVC4_PUBLIC;
+bool operator==(enum Result::Entailment e, const Result& r) CVC4_PUBLIC;
bool operator!=(enum Result::Sat s, const Result& r) CVC4_PUBLIC;
-bool operator!=(enum Result::Validity v, const Result& r) CVC4_PUBLIC;
+bool operator!=(enum Result::Entailment e, const Result& r) CVC4_PUBLIC;
} /* CVC4 namespace */
diff --git a/src/util/result.i b/src/util/result.i
index b77bfd881..cb835fbb0 100644
--- a/src/util/result.i
+++ b/src/util/result.i
@@ -8,13 +8,13 @@
%ignore CVC4::Result::operator!=(const Result& r) const;
%ignore CVC4::operator<<(std::ostream&, enum Result::Sat);
-%ignore CVC4::operator<<(std::ostream&, enum Result::Validity);
+%ignore CVC4::operator<<(std::ostream&, enum Result::Entailment);
%ignore CVC4::operator<<(std::ostream&, enum Result::UnknownExplanation);
%ignore CVC4::operator==(enum Result::Sat, const Result&);
%ignore CVC4::operator!=(enum Result::Sat, const Result&);
-%ignore CVC4::operator==(enum Result::Validity, const Result&);
-%ignore CVC4::operator!=(enum Result::Validity, const Result&);
+%ignore CVC4::operator==(enum Result::Entailment, const Result&);
+%ignore CVC4::operator!=(enum Result::Entailment, const Result&);
%include "util/result.h"
diff --git a/src/util/safe_print.h b/src/util/safe_print.h
index 75a517b18..fa9430f2c 100644
--- a/src/util/safe_print.h
+++ b/src/util/safe_print.h
@@ -21,6 +21,11 @@
** in statistics_registry.h would require specialization or we would have to
** use function overloading).
**
+ ** If there exists a function `toString(obj)` for a given object, it will be
+ ** used automatically. This is useful for printing enum values for example.
+ ** IMPORTANT: The `toString(obj)` function *must not* perform any allocations
+ ** or call other functions that are not async-signal-safe.
+ **
** This header is a "cvc4_private_library.h" header because it is private but
** the safe_print functions are used in the driver. See also the description
** of "statistics_registry.h" for more information on
@@ -41,6 +46,9 @@
#include <unistd.h>
+#include <cstring>
+#include <type_traits>
+
#include "lib/clock_gettime.h"
#include "util/result.h"
@@ -58,10 +66,51 @@ void CVC4_PUBLIC safe_print(int fd, const char (&msg)[N]) {
}
}
-/** Prints a variable of type T. Safe to use in a signal handler. */
+/**
+ * The default method for converting an object to a string for safe printing.
+ * This method simply returns "<unsupported>". The `long` argument is used to
+ * indicate that we do not prefer this method over the version that calls
+ * `toString()`.
+ */
+template <typename T>
+const char* toStringImpl(const T& obj, long)
+{
+ return "<unsupported>";
+}
+
+/**
+ * Returns the result of calling `toString(obj)`. This method is only defined
+ * if such an overload of `toString()` exists. To detect the existence of such
+ * a method, we use SFINAE and a trailing return type. The trailing return type
+ * is necessary because it allows us to refer to `obj`. The `int` argument is
+ * used to prefer this version of the function instead of the one that prints
+ * "<unsupported>".
+ */
+template <typename T>
+auto toStringImpl(const T& obj, int) -> decltype(toString(obj))
+{
+ return toString(obj);
+}
+
+/**
+ * Prints a variable of type T. Safe to use in a signal handler. The default
+ * implementation either prints "<unsupported>" or the result of calling
+ * `toString(obj)` if such a method exists (this is useful for printing enum
+ * values for example without implementing a template specialization here).
+ *
+ * @param fd The file descriptor to print to
+ * @param obj The object to print
+ */
template <typename T>
-void CVC4_PUBLIC safe_print(int fd, const T& msg) {
- safe_print(fd, "<unsupported>");
+void CVC4_PUBLIC safe_print(int fd, const T& obj)
+{
+ const char* s =
+ toStringImpl(obj, /* prefer the method that uses `toString()` */ 0);
+ ssize_t slen = static_cast<ssize_t>(strlen(s));
+ if (write(fd, s, slen) != slen)
+ {
+ abort();
+ }
}
template <>
diff --git a/src/util/string.cpp b/src/util/string.cpp
new file mode 100644
index 000000000..ff522ba7b
--- /dev/null
+++ b/src/util/string.cpp
@@ -0,0 +1,485 @@
+/********************* */
+/*! \file string.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Tim King, Tianyi Liang, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the string data type.
+ **/
+
+#include "util/string.h"
+
+#include <algorithm>
+#include <climits>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "base/check.h"
+#include "base/exception.h"
+
+using namespace std;
+
+namespace CVC4 {
+
+static_assert(UCHAR_MAX == 255, "Unsigned char is assumed to have 256 values.");
+
+String::String(const std::vector<unsigned> &s) : d_str(s)
+{
+#ifdef CVC4_ASSERTIONS
+ for (unsigned u : d_str)
+ {
+ Assert(u < num_codes());
+ }
+#endif
+}
+
+int String::cmp(const String &y) const {
+ if (size() != y.size()) {
+ return size() < y.size() ? -1 : 1;
+ }
+ for (unsigned int i = 0; i < size(); ++i) {
+ if (d_str[i] != y.d_str[i]) {
+ unsigned cp = d_str[i];
+ unsigned cpy = y.d_str[i];
+ return cp < cpy ? -1 : 1;
+ }
+ }
+ return 0;
+}
+
+String String::concat(const String &other) const {
+ std::vector<unsigned int> ret_vec(d_str);
+ ret_vec.insert(ret_vec.end(), other.d_str.begin(), other.d_str.end());
+ return String(ret_vec);
+}
+
+bool String::strncmp(const String& y, std::size_t n) const
+{
+ std::size_t b = (size() >= y.size()) ? size() : y.size();
+ std::size_t s = (size() <= y.size()) ? size() : y.size();
+ if (n > s) {
+ if (b == s) {
+ n = s;
+ } else {
+ return false;
+ }
+ }
+ for (std::size_t i = 0; i < n; ++i) {
+ if (d_str[i] != y.d_str[i]) return false;
+ }
+ return true;
+}
+
+bool String::rstrncmp(const String& y, std::size_t n) const
+{
+ std::size_t b = (size() >= y.size()) ? size() : y.size();
+ std::size_t s = (size() <= y.size()) ? size() : y.size();
+ if (n > s) {
+ if (b == s) {
+ n = s;
+ } else {
+ return false;
+ }
+ }
+ for (std::size_t i = 0; i < n; ++i) {
+ if (d_str[size() - i - 1] != y.d_str[y.size() - i - 1]) return false;
+ }
+ return true;
+}
+
+void String::addCharToInternal(unsigned char ch, std::vector<unsigned>& str)
+{
+ // if not a printable character
+ if (ch > 127 || ch < 32)
+ {
+ std::stringstream serr;
+ serr << "Illegal string character: \"" << ch
+ << "\", must use escape sequence";
+ throw CVC4::Exception(serr.str());
+ }
+ else
+ {
+ str.push_back(static_cast<unsigned>(ch));
+ }
+}
+
+std::vector<unsigned> String::toInternal(const std::string& s,
+ bool useEscSequences)
+{
+ std::vector<unsigned> str;
+ unsigned i = 0;
+ while (i < s.size())
+ {
+ // get the current character
+ char si = s[i];
+ if (si != '\\' || !useEscSequences)
+ {
+ addCharToInternal(si, str);
+ ++i;
+ continue;
+ }
+ // the vector of characters, in case we fail to read an escape sequence
+ std::vector<unsigned> nonEscCache;
+ // process the '\'
+ addCharToInternal(si, nonEscCache);
+ ++i;
+ // are we an escape sequence?
+ bool isEscapeSequence = true;
+ // the string corresponding to the hexidecimal code point
+ std::stringstream hexString;
+ // is the slash followed by a 'u'? Could be last character.
+ if (i >= s.size() || s[i] != 'u')
+ {
+ isEscapeSequence = false;
+ }
+ else
+ {
+ // process the 'u'
+ addCharToInternal(s[i], nonEscCache);
+ ++i;
+ bool isStart = true;
+ bool isEnd = false;
+ bool hasBrace = false;
+ while (i < s.size())
+ {
+ // add the next character
+ si = s[i];
+ if (isStart)
+ {
+ isStart = false;
+ // possibly read '{'
+ if (si == '{')
+ {
+ hasBrace = true;
+ addCharToInternal(si, nonEscCache);
+ ++i;
+ continue;
+ }
+ }
+ else if (si == '}')
+ {
+ // can only end if we had an open brace and read at least one digit
+ isEscapeSequence = hasBrace && !hexString.str().empty();
+ isEnd = true;
+ addCharToInternal(si, nonEscCache);
+ ++i;
+ break;
+ }
+ // must be a hex digit at this point
+ if (!isHexDigit(static_cast<unsigned>(si)))
+ {
+ isEscapeSequence = false;
+ break;
+ }
+ hexString << si;
+ addCharToInternal(si, nonEscCache);
+ ++i;
+ if (!hasBrace && hexString.str().size() == 4)
+ {
+ // will be finished reading \ u d_3 d_2 d_1 d_0 with no parens
+ isEnd = true;
+ break;
+ }
+ else if (hasBrace && hexString.str().size() > 5)
+ {
+ // too many digits enclosed in brace, not an escape sequence
+ isEscapeSequence = false;
+ break;
+ }
+ }
+ if (!isEnd)
+ {
+ // if we were interupted before ending, then this is not a valid
+ // escape sequence
+ isEscapeSequence = false;
+ }
+ }
+ if (isEscapeSequence)
+ {
+ Assert(!hexString.str().empty() && hexString.str().size() <= 5);
+ // Otherwise, we add the escaped character.
+ // This is guaranteed not to overflow due to the length of hstr.
+ uint32_t val;
+ hexString >> std::hex >> val;
+ if (val > num_codes())
+ {
+ // Failed due to being out of range. This can happen for strings of
+ // the form \ u { d_4 d_3 d_2 d_1 d_0 } where d_4 is a hexidecimal not
+ // in the range [0-2].
+ isEscapeSequence = false;
+ }
+ else
+ {
+ str.push_back(val);
+ }
+ }
+ // if we did not successfully parse an escape sequence, we add back all
+ // characters that we cached
+ if (!isEscapeSequence)
+ {
+ str.insert(str.end(), nonEscCache.begin(), nonEscCache.end());
+ }
+ }
+#ifdef CVC4_ASSERTIONS
+ for (unsigned u : str)
+ {
+ Assert(u < num_codes());
+ }
+#endif
+ return str;
+}
+
+unsigned String::front() const
+{
+ Assert(!d_str.empty());
+ return d_str.front();
+}
+
+unsigned String::back() const
+{
+ Assert(!d_str.empty());
+ return d_str.back();
+}
+
+std::size_t String::overlap(const String &y) const {
+ std::size_t i = size() < y.size() ? size() : y.size();
+ for (; i > 0; i--) {
+ String s = suffix(i);
+ String p = y.prefix(i);
+ if (s == p) {
+ return i;
+ }
+ }
+ return i;
+}
+
+std::size_t String::roverlap(const String &y) const {
+ std::size_t i = size() < y.size() ? size() : y.size();
+ for (; i > 0; i--) {
+ String s = prefix(i);
+ String p = y.suffix(i);
+ if (s == p) {
+ return i;
+ }
+ }
+ return i;
+}
+
+std::string String::toString(bool useEscSequences) const {
+ std::stringstream str;
+ for (unsigned int i = 0; i < size(); ++i) {
+ // we always print forward slash as a code point so that it cannot
+ // be interpreted as specifying part of a code point, e.g. the string
+ // '\' + 'u' + '0' of length three.
+ if (isPrintable(d_str[i]) && d_str[i] != '\\' && !useEscSequences)
+ {
+ str << static_cast<char>(d_str[i]);
+ }
+ else
+ {
+ std::stringstream ss;
+ ss << std::hex << d_str[i];
+ str << "\\u{" << ss.str() << "}";
+ }
+ }
+ return str.str();
+}
+
+bool String::isLeq(const String &y) const
+{
+ for (unsigned i = 0; i < size(); ++i)
+ {
+ if (i >= y.size())
+ {
+ return false;
+ }
+ unsigned ci = d_str[i];
+ unsigned cyi = y.d_str[i];
+ if (ci > cyi)
+ {
+ return false;
+ }
+ if (ci < cyi)
+ {
+ return true;
+ }
+ }
+ return true;
+}
+
+bool String::isRepeated() const {
+ if (size() > 1) {
+ unsigned int f = d_str[0];
+ for (unsigned i = 1; i < size(); ++i) {
+ if (f != d_str[i]) return false;
+ }
+ }
+ return true;
+}
+
+bool String::tailcmp(const String &y, int &c) const {
+ int id_x = size() - 1;
+ int id_y = y.size() - 1;
+ while (id_x >= 0 && id_y >= 0) {
+ if (d_str[id_x] != y.d_str[id_y]) {
+ c = id_x;
+ return false;
+ }
+ --id_x;
+ --id_y;
+ }
+ c = id_x == -1 ? (-(id_y + 1)) : (id_x + 1);
+ return true;
+}
+
+std::size_t String::find(const String &y, const std::size_t start) const {
+ if (size() < y.size() + start) return std::string::npos;
+ if (y.empty()) return start;
+ if (empty()) return std::string::npos;
+
+ std::vector<unsigned>::const_iterator itr = std::search(
+ d_str.begin() + start, d_str.end(), y.d_str.begin(), y.d_str.end());
+ if (itr != d_str.end()) {
+ return itr - d_str.begin();
+ }
+ return std::string::npos;
+}
+
+std::size_t String::rfind(const String &y, const std::size_t start) const {
+ if (size() < y.size() + start) return std::string::npos;
+ if (y.empty()) return start;
+ if (empty()) return std::string::npos;
+
+ std::vector<unsigned>::const_reverse_iterator itr = std::search(
+ d_str.rbegin() + start, d_str.rend(), y.d_str.rbegin(), y.d_str.rend());
+ if (itr != d_str.rend()) {
+ return itr - d_str.rbegin();
+ }
+ return std::string::npos;
+}
+
+bool String::hasPrefix(const String& y) const
+{
+ size_t s = size();
+ size_t ys = y.size();
+ if (ys > s)
+ {
+ return false;
+ }
+ for (size_t i = 0; i < ys; i++)
+ {
+ if (d_str[i] != y.d_str[i])
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool String::hasSuffix(const String& y) const
+{
+ size_t s = size();
+ size_t ys = y.size();
+ if (ys > s)
+ {
+ return false;
+ }
+ size_t idiff = s - ys;
+ for (size_t i = 0; i < ys; i++)
+ {
+ if (d_str[i + idiff] != y.d_str[i])
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+String String::replace(const String &s, const String &t) const {
+ std::size_t ret = find(s);
+ if (ret != std::string::npos) {
+ std::vector<unsigned int> vec;
+ vec.insert(vec.begin(), d_str.begin(), d_str.begin() + ret);
+ vec.insert(vec.end(), t.d_str.begin(), t.d_str.end());
+ vec.insert(vec.end(), d_str.begin() + ret + s.size(), d_str.end());
+ return String(vec);
+ } else {
+ return *this;
+ }
+}
+
+String String::substr(std::size_t i) const {
+ Assert(i <= size());
+ std::vector<unsigned int> ret_vec;
+ std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
+ ret_vec.insert(ret_vec.end(), itr, d_str.end());
+ return String(ret_vec);
+}
+
+String String::substr(std::size_t i, std::size_t j) const {
+ Assert(i + j <= size());
+ std::vector<unsigned int> ret_vec;
+ std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
+ ret_vec.insert(ret_vec.end(), itr, itr + j);
+ return String(ret_vec);
+}
+
+bool String::noOverlapWith(const String& y) const
+{
+ return y.find(*this) == std::string::npos
+ && this->find(y) == std::string::npos && this->overlap(y) == 0
+ && y.overlap(*this) == 0;
+}
+
+bool String::isNumber() const {
+ if (d_str.empty()) {
+ return false;
+ }
+ for (unsigned character : d_str) {
+ if (!isDigit(character))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool String::isDigit(unsigned character)
+{
+ // '0' to '9'
+ return 48 <= character && character <= 57;
+}
+
+bool String::isHexDigit(unsigned character)
+{
+ // '0' to '9' or 'A' to 'F' or 'a' to 'f'
+ return isDigit(character) || (65 <= character && character <= 70)
+ || (97 <= character && character <= 102);
+}
+
+bool String::isPrintable(unsigned character)
+{
+ // Unicode 0x00020 (' ') to 0x0007E ('~')
+ return 32 <= character && character <= 126;
+}
+
+size_t String::maxSize() { return std::numeric_limits<uint32_t>::max(); }
+
+Rational String::toNumber() const
+{
+ // when smt2 standard for strings is set, this may change, based on the
+ // semantics of str.from.int for leading zeros
+ return Rational(toString());
+}
+
+std::ostream &operator<<(std::ostream &os, const String &s) {
+ return os << "\"" << s.toString(true) << "\"";
+}
+
+} // namespace CVC4
diff --git a/src/util/string.h b/src/util/string.h
new file mode 100644
index 000000000..032105812
--- /dev/null
+++ b/src/util/string.h
@@ -0,0 +1,271 @@
+/********************* */
+/*! \file string.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Tim King, Tianyi Liang
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The string data type.
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__UTIL__STRING_H
+#define CVC4__UTIL__STRING_H
+
+#include <cstddef>
+#include <functional>
+#include <ostream>
+#include <string>
+#include <vector>
+#include "util/rational.h"
+
+namespace CVC4 {
+
+/** The CVC4 string class
+ *
+ * This data structure is the domain of values for the string type. It can also
+ * be used as a generic utility for representing strings.
+ */
+class CVC4_PUBLIC String {
+ public:
+ /**
+ * This is the cardinality of the alphabet that is representable by this
+ * class. Notice that this must be greater than or equal to the cardinality
+ * of the alphabet that the string theory reasons about.
+ *
+ * This must be strictly less than std::numeric_limits<unsigned>::max().
+ *
+ * As per the SMT-LIB standard for strings, we support the first 3 planes of
+ * Unicode characters, where 196608 = 3*16^4.
+ */
+ static inline unsigned num_codes() { return 196608; }
+ /** constructors for String
+ *
+ * Internally, a CVC4::String is represented by a vector of unsigned
+ * integers (d_str) representing the code points of the characters.
+ *
+ * To build a string from a C++ string, we may process escape sequences
+ * according to the SMT-LIB standard. In particular, if useEscSequences is
+ * true, we convert unicode escape sequences:
+ * \u d_3 d_2 d_1 d_0
+ * \u{d_0}
+ * \u{d_1 d_0}
+ * \u{d_2 d_1 d_0}
+ * \u{d_3 d_2 d_1 d_0}
+ * \u{d_4 d_3 d_2 d_1 d_0}
+ * where d_0 ... d_4 are hexidecimal digits, to the appropriate character.
+ *
+ * If useEscSequences is false, then the characters of the constructed
+ * CVC4::String correspond one-to-one with the input string.
+ */
+ String() = default;
+ explicit String(const std::string& s, bool useEscSequences = false)
+ : d_str(toInternal(s, useEscSequences))
+ {
+ }
+ explicit String(const char* s, bool useEscSequences = false)
+ : d_str(toInternal(std::string(s), useEscSequences))
+ {
+ }
+ explicit String(const std::vector<unsigned>& s);
+
+ String& operator=(const String& y) {
+ if (this != &y) {
+ d_str = y.d_str;
+ }
+ return *this;
+ }
+
+ String concat(const String& other) const;
+
+ bool operator==(const String& y) const { return cmp(y) == 0; }
+ bool operator!=(const String& y) const { return cmp(y) != 0; }
+ bool operator<(const String& y) const { return cmp(y) < 0; }
+ bool operator>(const String& y) const { return cmp(y) > 0; }
+ bool operator<=(const String& y) const { return cmp(y) <= 0; }
+ bool operator>=(const String& y) const { return cmp(y) >= 0; }
+
+ /**
+ * Returns true if this string is equal to y for their first n characters.
+ * If n is larger than the length of this string or y, this method returns
+ * true if and only if this string is equal to y.
+ */
+ bool strncmp(const String& y, std::size_t n) const;
+ /**
+ * Returns true if this string is equal to y for their last n characters.
+ * Similar to strncmp, if n is larger than the length of this string or y,
+ * this method returns true if and only if this string is equal to y.
+ */
+ bool rstrncmp(const String& y, std::size_t n) const;
+
+ /* toString
+ * Converts this string to a std::string.
+ *
+ * The unprintable characters are converted to unicode escape sequences as
+ * described above.
+ *
+ * If useEscSequences is false, the string's printable characters are
+ * printed as characters. Notice that for all std::string s having only
+ * printable characters, we have that
+ * CVC4::String( s ).toString() = s.
+ */
+ std::string toString(bool useEscSequences = false) const;
+ /** is this the empty string? */
+ bool empty() const { return d_str.empty(); }
+ /** is this the empty string? */
+ bool isEmptyString() const { return empty(); }
+ /** is less than or equal to string y */
+ bool isLeq(const String& y) const;
+ /** Return the length of the string */
+ std::size_t size() const { return d_str.size(); }
+
+ bool isRepeated() const;
+ bool tailcmp(const String& y, int& c) const;
+
+ /**
+ * Return the first position y occurs in this string, or std::string::npos
+ * otherwise.
+ */
+ std::size_t find(const String& y, const std::size_t start = 0) const;
+ /**
+ * Return the first position y occurs in this string searching from the end,
+ * or std::string::npos otherwise.
+ */
+ std::size_t rfind(const String& y, const std::size_t start = 0) const;
+ /** Returns true if y is a prefix of this */
+ bool hasPrefix(const String& y) const;
+ /** Returns true if y is a suffix of this */
+ bool hasSuffix(const String& y) const;
+ /** Replace the first occurrence of s in this string with t */
+ String replace(const String& s, const String& t) const;
+ /** Return the substring of this string starting at index i */
+ String substr(std::size_t i) const;
+ /** Return the substring of this string starting at index i with size at most
+ * j */
+ String substr(std::size_t i, std::size_t j) const;
+ /** Return the prefix of this string of size at most i */
+ String prefix(std::size_t i) const { return substr(0, i); }
+ /** Return the suffix of this string of size at most i */
+ String suffix(std::size_t i) const { return substr(size() - i, i); }
+
+ /**
+ * Checks if there is any overlap between this string and another string. This
+ * corresponds to checking whether one string contains the other and whether a
+ * substring of one is a prefix of the other and vice-versa.
+ *
+ * @param y The other string
+ * @return True if there is an overlap, false otherwise
+ */
+ bool noOverlapWith(const String& y) const;
+
+ /** string overlap
+ *
+ * if overlap returns m>0,
+ * then the maximal suffix of this string that is a prefix of y is of length m.
+ *
+ * For example, if x is "abcdef", then:
+ * x.overlap("defg") = 3
+ * x.overlap("ab") = 0
+ * x.overlap("d") = 0
+ * x.overlap("bcdefdef") = 5
+ */
+ std::size_t overlap(const String& y) const;
+ /** string reverse overlap
+ *
+ * if roverlap returns m>0,
+ * then the maximal prefix of this string that is a suffix of y is of length m.
+ *
+ * For example, if x is "abcdef", then:
+ * x.roverlap("aaabc") = 3
+ * x.roverlap("def") = 0
+ * x.roverlap("d") = 0
+ * x.roverlap("defabcde") = 5
+ *
+ * Notice that x.overlap(y) = y.roverlap(x)
+ */
+ std::size_t roverlap(const String& y) const;
+
+ /**
+ * Returns true if this string corresponds in text to a number, for example
+ * this returns true for strings "7", "12", "004", "0" and false for strings
+ * "abc", "4a", "-4", "".
+ */
+ bool isNumber() const;
+ /** Returns the corresponding rational for the text of this string. */
+ Rational toNumber() const;
+ /** Get the unsigned representation (code points) of this string */
+ const std::vector<unsigned>& getVec() const { return d_str; }
+ /**
+ * Get the unsigned (code point) value of the first character in this string
+ */
+ unsigned front() const;
+ /**
+ * Get the unsigned (code point) value of the last character in this string
+ */
+ unsigned back() const;
+ /** is the unsigned a digit?
+ *
+ * This is true for code points between 48 ('0') and 57 ('9').
+ */
+ static bool isDigit(unsigned character);
+ /** is the unsigned a hexidecimal digit?
+ *
+ * This is true for code points between 48 ('0') and 57 ('9'), code points
+ * between 65 ('A') and 70 ('F) and code points between 97 ('a') and 102 ('f).
+ */
+ static bool isHexDigit(unsigned character);
+ /** is the unsigned a printable code point?
+ *
+ * This is true for Unicode 32 (' ') to 126 ('~').
+ */
+ static bool isPrintable(unsigned character);
+
+ /**
+ * Returns the maximum length of string representable by this class.
+ * Corresponds to the maximum size of d_str.
+ */
+ static size_t maxSize();
+ private:
+ /**
+ * Helper for toInternal: add character ch to vector vec, storing a string in
+ * internal format. This throws an error if ch is not a printable character,
+ * since non-printable characters must be escaped in SMT-LIB.
+ */
+ static void addCharToInternal(unsigned char ch, std::vector<unsigned>& vec);
+ /**
+ * Convert the string s to the internal format (vector of code points).
+ * The argument useEscSequences is whether to process unicode escape
+ * sequences.
+ */
+ static std::vector<unsigned> toInternal(const std::string& s,
+ bool useEscSequences);
+
+ /**
+ * Returns a negative number if *this < y, 0 if *this and y are equal and a
+ * positive number if *this > y.
+ */
+ int cmp(const String& y) const;
+
+ std::vector<unsigned> d_str;
+}; /* class String */
+
+namespace strings {
+
+struct CVC4_PUBLIC StringHashFunction {
+ size_t operator()(const ::CVC4::String& s) const {
+ return std::hash<std::string>()(s.toString());
+ }
+}; /* struct StringHashFunction */
+
+} // namespace strings
+
+std::ostream& operator<<(std::ostream& os, const String& s) CVC4_PUBLIC;
+
+} // namespace CVC4
+
+#endif /* CVC4__UTIL__STRING_H */
diff --git a/src/util/string.i b/src/util/string.i
new file mode 100644
index 000000000..1ded901aa
--- /dev/null
+++ b/src/util/string.i
@@ -0,0 +1,25 @@
+%{
+#include "util/string.h"
+%}
+
+%rename(CVC4String) String;
+%rename(CVC4StringHashFunction) CVC4::strings::StringHashFunction;
+
+%ignore CVC4::String::String(const std::string&);
+
+%rename(assign) CVC4::String::operator=(const String&);
+%rename(getChar) CVC4::String::operator[](const unsigned int) const;
+%rename(equals) CVC4::String::operator==(const String&) const;
+%ignore CVC4::String::operator!=(const String&) const;
+%rename(less) CVC4::String::operator<(const String&) const;
+%rename(lessEqual) CVC4::String::operator<=(const String&) const;
+%rename(greater) CVC4::String::operator>(const String&) const;
+%rename(greaterEqual) CVC4::String::operator>=(const String&) const;
+
+%rename(apply) CVC4::strings::StringHashFunction::operator()(const ::CVC4::String&) const;
+
+%ignore CVC4::operator<<(std::ostream&, const String&);
+
+%apply int &OUTPUT { int &c };
+%include "util/string.h"
+%clear int &c;
diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt
index 0eb6bc2d2..87bea4583 100644
--- a/test/regress/CMakeLists.txt
+++ b/test/regress/CMakeLists.txt
@@ -610,6 +610,8 @@ set(regress_0_tests
regress0/parser/as.smt2
regress0/parser/bv_arity_smt2.6.smt2
regress0/parser/bv_nat.smt2
+ regress0/parser/choice.cvc
+ regress0/parser/choice.smt2
regress0/parser/constraint.smt2
regress0/parser/declarefun-emptyset-uf.smt2
regress0/parser/force_logic_set_logic.smt2
@@ -902,6 +904,7 @@ set(regress_0_tests
regress0/smtlib/global-decls.smt2
regress0/smtlib/issue4028.smt2
regress0/smtlib/issue4077.smt2
+ regress0/smtlib/issue4151.smt2
regress0/smtlib/reason-unknown.smt2
regress0/smtlib/reset.smt2
regress0/smtlib/reset-assertions1.smt2
@@ -915,6 +918,7 @@ set(regress_0_tests
regress0/strings/bug002.smt2
regress0/strings/bug612.smt2
regress0/strings/bug613.smt2
+ regress0/strings/char-representations.smt2
regress0/strings/code-eval.smt2
regress0/strings/code-perf.smt2
regress0/strings/code-sat-neg-one.smt2
@@ -922,6 +926,7 @@ set(regress_0_tests
regress0/strings/escchar.smt2
regress0/strings/escchar_25.smt2
regress0/strings/from_code.smt2
+ regress0/strings/gen-esc-seq.smt2
regress0/strings/hconst-092618.smt2
regress0/strings/idof-rewrites.smt2
regress0/strings/idof-sem.smt2
@@ -938,7 +943,10 @@ set(regress_0_tests
regress0/strings/large-model.smt2
regress0/strings/leadingzero001.smt2
regress0/strings/loop001.smt2
+ regress0/strings/loop-wrong-sem.smt2
regress0/strings/model001.smt2
+ regress0/strings/model-code-point.smt2
+ regress0/strings/model-friendly.smt2
regress0/strings/ncontrib-rewrites.smt2
regress0/strings/norn-31.smt2
regress0/strings/norn-simp-rew.smt2
@@ -967,6 +975,7 @@ set(regress_0_tests
regress0/strings/tolower-rrs.smt2
regress0/strings/tolower-simple.smt2
regress0/strings/type001.smt2
+ regress0/strings/unicode-esc.smt2
regress0/strings/unsound-0908.smt2
regress0/strings/unsound-repl-rewrite.smt2
regress0/sygus/General_plus10.sy
@@ -1857,7 +1866,6 @@ set(regress_1_tests
regress1/sygus/issue3498.smt2
regress1/sygus/issue3514.smt2
regress1/sygus/issue3507.smt2
- regress1/sygus/issue3580.sy
regress1/sygus/issue3633.smt2
regress1/sygus/issue3634.smt2
regress1/sygus/issue3635.smt2
@@ -2388,6 +2396,8 @@ set(regression_disabled_tests
regress1/sygus/array_search_2.sy
regress1/sygus/array_sum_2_5.sy
regress1/sygus/crcy-si-rcons.sy
+ # currently slow at c9fd28a
+ regress1/sygus/issue3580.sy
regress2/arith/arith-int-098.cvc
regress2/arith/miplib-opt1217--27.smt2
regress2/arith/miplib-pp08a-3000.smt2
diff --git a/test/regress/regress0/arith/arith.01.cvc b/test/regress/regress0/arith/arith.01.cvc
index 1de397ab1..08d591590 100644
--- a/test/regress/regress0/arith/arith.01.cvc
+++ b/test/regress/regress0/arith/arith.01.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x : REAL;
y : REAL;
diff --git a/test/regress/regress0/arith/arith.02.cvc b/test/regress/regress0/arith/arith.02.cvc
index d7b0291f7..e0a48c357 100644
--- a/test/regress/regress0/arith/arith.02.cvc
+++ b/test/regress/regress0/arith/arith.02.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x : REAL;
y : REAL;
z : REAL;
diff --git a/test/regress/regress0/arith/arith.03.cvc b/test/regress/regress0/arith/arith.03.cvc
index 288c341ef..ce54c8b7e 100644
--- a/test/regress/regress0/arith/arith.03.cvc
+++ b/test/regress/regress0/arith/arith.03.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x : REAL;
y : REAL;
diff --git a/test/regress/regress0/arith/bug549.cvc b/test/regress/regress0/arith/bug549.cvc
index 54df5e62c..bfb3e75d5 100644
--- a/test/regress/regress0/arith/bug549.cvc
+++ b/test/regress/regress0/arith/bug549.cvc
@@ -1,3 +1,3 @@
-% EXPECT: valid
+% EXPECT: entailed
a, b : REAL;
-QUERY (a*b)^5 = b*a*a*a*a*b*b*b*b*a; \ No newline at end of file
+QUERY (a*b)^5 = b*a*a*a*a*b*b*b*b*a;
diff --git a/test/regress/regress0/arith/integers/arith-int-014.cvc b/test/regress/regress0/arith/integers/arith-int-014.cvc
index 265d18a84..84954a3ea 100644
--- a/test/regress/regress0/arith/integers/arith-int-014.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-014.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (10 * x0) + (25 * x1) + (10 * x2) + (-28 * x3) <= 20 ;
ASSERT (24 * x0) + (-9 * x1) + (-12 * x2) + (15 * x3) <= 3;
diff --git a/test/regress/regress0/arith/integers/arith-int-015.cvc b/test/regress/regress0/arith/integers/arith-int-015.cvc
index d2e2639ab..8f8b01fc9 100644
--- a/test/regress/regress0/arith/integers/arith-int-015.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-015.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-22 * x0) + (-3 * x1) + (9 * x2) + (-13 * x3) > -31 ;
ASSERT (31 * x0) + (-17 * x1) + (28 * x2) + (-16 * x3) > -28;
diff --git a/test/regress/regress0/arith/integers/arith-int-021.cvc b/test/regress/regress0/arith/integers/arith-int-021.cvc
index 345c90899..66f02401b 100644
--- a/test/regress/regress0/arith/integers/arith-int-021.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-021.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (8 * x0) + (-27 * x1) + (29 * x2) + (-13 * x3) < 12;
QUERY FALSE;
diff --git a/test/regress/regress0/arith/integers/arith-int-023.cvc b/test/regress/regress0/arith/integers/arith-int-023.cvc
index 01d51a226..b3d79e8ff 100644
--- a/test/regress/regress0/arith/integers/arith-int-023.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-023.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (29 * x0) + (-19 * x1) + (23 * x2) + (15 * x3) <= 9;
QUERY FALSE;
diff --git a/test/regress/regress0/arith/integers/arith-int-025.cvc b/test/regress/regress0/arith/integers/arith-int-025.cvc
index 5a11212d5..e905da9a0 100644
--- a/test/regress/regress0/arith/integers/arith-int-025.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-025.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-19 * x0) + (-29 * x1) + (2 * x2) + (26 * x3) >= 3;
QUERY FALSE;
diff --git a/test/regress/regress0/arith/integers/arith-int-042.cvc b/test/regress/regress0/arith/integers/arith-int-042.cvc
index c38231695..b6db26e86 100644
--- a/test/regress/regress0/arith/integers/arith-int-042.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-042.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-9 * x0) + (25 * x1) + (0 * x2) + (13 * x3) = 17 ;
ASSERT (-6 * x0) + (32 * x1) + (2 * x2) + (-32 * x3) = -5 ;
diff --git a/test/regress/regress0/arith/integers/arith-int-042.min.cvc b/test/regress/regress0/arith/integers/arith-int-042.min.cvc
index 77571e526..3fd20a0b6 100644
--- a/test/regress/regress0/arith/integers/arith-int-042.min.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-042.min.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x1: INT;
x0: INT;
QUERY NOT (((x0 * 6) + (x1 * 32)) = 1);
diff --git a/test/regress/regress0/arith/integers/arith-int-079.cvc b/test/regress/regress0/arith/integers/arith-int-079.cvc
index 7fa2fc937..1739b3364 100644
--- a/test/regress/regress0/arith/integers/arith-int-079.cvc
+++ b/test/regress/regress0/arith/integers/arith-int-079.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (6 * x0) + (2 * x1) + (22 * x2) + (-18 * x3) = -15 ;
ASSERT (-8 * x0) + (-25 * x1) + (-25 * x2) + (7 * x3) > 10 ;
diff --git a/test/regress/regress0/arith/integers/arith-interval.cvc b/test/regress/regress0/arith/integers/arith-interval.cvc
index d79ec94a7..ed6cb747e 100644
--- a/test/regress/regress0/arith/integers/arith-interval.cvc
+++ b/test/regress/regress0/arith/integers/arith-interval.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x: INT;
P: INT -> BOOLEAN;
diff --git a/test/regress/regress0/boolean-prec.cvc b/test/regress/regress0/boolean-prec.cvc
index 9d1029cbf..07a2aa2f5 100644
--- a/test/regress/regress0/boolean-prec.cvc
+++ b/test/regress/regress0/boolean-prec.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of AND, <=>, NOT.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/bug310.cvc b/test/regress/regress0/bug310.cvc
index 0cb6cf0fe..12cb80494 100644
--- a/test/regress/regress0/bug310.cvc
+++ b/test/regress/regress0/bug310.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
b : BOOLEAN;
DATATYPE D = c(s:INT) END;
QUERY c(IF b THEN 1 ELSE 0 ENDIF) = IF b THEN c(1) ELSE c(0) ENDIF;
diff --git a/test/regress/regress0/bug32.cvc b/test/regress/regress0/bug32.cvc
index 304dd6ec4..400f55885 100644
--- a/test/regress/regress0/bug32.cvc
+++ b/test/regress/regress0/bug32.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
a:BOOLEAN;
b:BOOLEAN;
ASSERT(a);
diff --git a/test/regress/regress0/bug322b.cvc b/test/regress/regress0/bug322b.cvc
index fa9462f64..0e06cbc13 100644
--- a/test/regress/regress0/bug322b.cvc
+++ b/test/regress/regress0/bug322b.cvc
@@ -1,7 +1,7 @@
% COMMAND-LINE: --incremental
-% EXPECT: valid
-% EXPECT: valid
-% EXPECT: valid
+% EXPECT: entailed
+% EXPECT: entailed
+% EXPECT: entailed
x : INT;
y : INT = x + 1;
z : INT = -10;
diff --git a/test/regress/regress0/bug486.cvc b/test/regress/regress0/bug486.cvc
index c51af4e24..665bcdafb 100644
--- a/test/regress/regress0/bug486.cvc
+++ b/test/regress/regress0/bug486.cvc
@@ -1,6 +1,6 @@
% COMMAND-LINE: --finite-model-find -i
-% EXPECT: invalid
-% EXPECT: valid
+% EXPECT: not_entailed
+% EXPECT: entailed
prin:TYPE;
form:TYPE;
diff --git a/test/regress/regress0/bv/bvcomp.cvc b/test/regress/regress0/bv/bvcomp.cvc
index b9b4b8e17..17064a2f2 100644
--- a/test/regress/regress0/bv/bvcomp.cvc
+++ b/test/regress/regress0/bv/bvcomp.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x : BITVECTOR(10);
diff --git a/test/regress/regress0/bv/bvsimple.cvc b/test/regress/regress0/bv/bvsimple.cvc
index dcacd643a..6bc649a03 100644
--- a/test/regress/regress0/bv/bvsimple.cvc
+++ b/test/regress/regress0/bv/bvsimple.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Some tests from the CVC3 user manual.
% http://www.cs.nyu.edu/acsys/cvc3/doc/user_doc.html
diff --git a/test/regress/regress0/cvc-rerror-print.cvc b/test/regress/regress0/cvc-rerror-print.cvc
index dd05723d2..e134b5666 100644
--- a/test/regress/regress0/cvc-rerror-print.cvc
+++ b/test/regress/regress0/cvc-rerror-print.cvc
@@ -1,5 +1,5 @@
-% EXPECT: valid
-% EXPECT: Cannot get model unless immediately preceded by SAT/INVALID or UNKNOWN response.
+% EXPECT: entailed
+% EXPECT: Cannot get model unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN response.
OPTION "logic" "ALL";
OPTION "produce-models" true;
x : INT;
diff --git a/test/regress/regress0/cvc3-bug15.cvc b/test/regress/regress0/cvc3-bug15.cvc
index 860ce38bd..779a2eab4 100644
--- a/test/regress/regress0/cvc3-bug15.cvc
+++ b/test/regress/regress0/cvc3-bug15.cvc
@@ -1,5 +1,5 @@
%% This test borrowed from CVC3 regressions, bug15.cvc
-% EXPECT: valid
+% EXPECT: entailed
x : REAL;
y : REAL;
f : REAL -> REAL;
diff --git a/test/regress/regress0/cvc3.userdoc.01.cvc b/test/regress/regress0/cvc3.userdoc.01.cvc
index 7c89de4ac..e3e9aaf0a 100644
--- a/test/regress/regress0/cvc3.userdoc.01.cvc
+++ b/test/regress/regress0/cvc3.userdoc.01.cvc
@@ -1,31 +1,31 @@
% COMMAND-LINE: --incremental
-% EXPECT: valid
+% EXPECT: entailed
QUERY 0bin0000111101010000 = 0hex0f50;
-% EXPECT: valid
+% EXPECT: entailed
QUERY 0bin01@0bin0 = 0bin010;
-% EXPECT: valid
+% EXPECT: entailed
QUERY 0bin0011[3:1] = 0bin001;
-% EXPECT: valid
+% EXPECT: entailed
QUERY 0bin0011 << 3 = 0bin0011000;
-% EXPECT: valid
+% EXPECT: entailed
QUERY 0bin1000 >> 3 = 0bin0001;
-% EXPECT: valid
+% EXPECT: entailed
QUERY SX(0bin100, 5) = 0bin11100;
-% EXPECT: valid
+% EXPECT: entailed
QUERY BVZEROEXTEND(0bin1,3) = 0bin0001;
-% EXPECT: valid
+% EXPECT: entailed
QUERY BVREPEAT(0bin10,3) = 0bin101010;
-% EXPECT: valid
+% EXPECT: entailed
QUERY BVROTL(0bin101,1) = 0bin011;
-% EXPECT: valid
+% EXPECT: entailed
QUERY BVROTR(0bin101,1) = 0bin110;
diff --git a/test/regress/regress0/cvc3.userdoc.02.cvc b/test/regress/regress0/cvc3.userdoc.02.cvc
index b6329e953..e143ea275 100644
--- a/test/regress/regress0/cvc3.userdoc.02.cvc
+++ b/test/regress/regress0/cvc3.userdoc.02.cvc
@@ -2,6 +2,6 @@ x : BITVECTOR(5);
y : BITVECTOR(4);
yy : BITVECTOR(3);
-% EXPECT: valid
+% EXPECT: entailed
QUERY
BVPLUS(9, x@0bin0000, (0bin000@(~y)@0bin11))[8:4] = BVPLUS(5, x, ~(y[3:2])) ;
diff --git a/test/regress/regress0/cvc3.userdoc.03.cvc b/test/regress/regress0/cvc3.userdoc.03.cvc
index 4fc6a5f8c..3b3829ebc 100644
--- a/test/regress/regress0/cvc3.userdoc.03.cvc
+++ b/test/regress/regress0/cvc3.userdoc.03.cvc
@@ -1,7 +1,7 @@
bv : BITVECTOR(10);
a : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY
0bin01100000[5:3]=(0bin1111001@bv[0:0])[4:2]
AND
diff --git a/test/regress/regress0/cvc3.userdoc.04.cvc b/test/regress/regress0/cvc3.userdoc.04.cvc
index 824690bcf..da8b1e82c 100644
--- a/test/regress/regress0/cvc3.userdoc.04.cvc
+++ b/test/regress/regress0/cvc3.userdoc.04.cvc
@@ -5,5 +5,5 @@ ASSERT x&y&t&z&q = x;
ASSERT x|y = t;
ASSERT BVXOR(x,~x) = t;
-% EXPECT: valid
+% EXPECT: entailed
QUERY FALSE;
diff --git a/test/regress/regress0/cvc3.userdoc.05.cvc b/test/regress/regress0/cvc3.userdoc.05.cvc
index 37da96b3c..85e0c2105 100644
--- a/test/regress/regress0/cvc3.userdoc.05.cvc
+++ b/test/regress/regress0/cvc3.userdoc.05.cvc
@@ -3,7 +3,7 @@ x, y : BITVECTOR(4);
ASSERT x = 0hex5;
ASSERT y = 0bin0101;
-% EXPECT: valid
+% EXPECT: entailed
QUERY
BVMULT(8,x,y)=BVMULT(8,y,x)
AND
diff --git a/test/regress/regress0/cvc3.userdoc.06.cvc b/test/regress/regress0/cvc3.userdoc.06.cvc
index 3801b6d53..3968365ad 100644
--- a/test/regress/regress0/cvc3.userdoc.06.cvc
+++ b/test/regress/regress0/cvc3.userdoc.06.cvc
@@ -6,8 +6,8 @@ z, t : BITVECTOR(12);
ASSERT x = 0hexff;
ASSERT z = 0hexff0;
-% EXPECT: valid
+% EXPECT: entailed
QUERY z = x << 4;
-% EXPECT: valid
+% EXPECT: entailed
QUERY (z >> 4)[7:0] = x;
diff --git a/test/regress/regress0/datatypes/bug286.cvc b/test/regress/regress0/datatypes/bug286.cvc
index 501f5f737..33a320acd 100644
--- a/test/regress/regress0/datatypes/bug286.cvc
+++ b/test/regress/regress0/datatypes/bug286.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE foo = f(i:INT) END;
x : foo;
y : INT;
diff --git a/test/regress/regress0/datatypes/datatype-dump.cvc b/test/regress/regress0/datatypes/datatype-dump.cvc
index 8e2818106..e28fc6305 100644
--- a/test/regress/regress0/datatypes/datatype-dump.cvc
+++ b/test/regress/regress0/datatypes/datatype-dump.cvc
@@ -10,7 +10,7 @@
% EXPECT: END;
% EXPECT: x : nat;
% EXPECT: QUERY NOT(is_succ(x)) AND NOT(is_zero(x));
-% EXPECT: invalid
+% EXPECT: not_entailed
%
DATATYPE nat = succ(pred : nat) | zero END;
diff --git a/test/regress/regress0/datatypes/datatype.cvc b/test/regress/regress0/datatypes/datatype.cvc
index 20fec4fdd..6a0e97fc3 100644
--- a/test/regress/regress0/datatypes/datatype.cvc
+++ b/test/regress/regress0/datatypes/datatype.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE nat = succ(pred : nat) | zero END;
diff --git a/test/regress/regress0/datatypes/datatype0.cvc b/test/regress/regress0/datatypes/datatype0.cvc
index 8fff50a86..0b9e41024 100644
--- a/test/regress/regress0/datatypes/datatype0.cvc
+++ b/test/regress/regress0/datatypes/datatype0.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE nat = succ(pred : nat) | zero END;
diff --git a/test/regress/regress0/datatypes/datatype1.cvc b/test/regress/regress0/datatypes/datatype1.cvc
index 3934959f1..9e746c0e4 100644
--- a/test/regress/regress0/datatypes/datatype1.cvc
+++ b/test/regress/regress0/datatypes/datatype1.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
tree = node(left : tree, right : tree) | leaf
diff --git a/test/regress/regress0/datatypes/datatype13.cvc b/test/regress/regress0/datatypes/datatype13.cvc
index 91e582dbd..78d28be00 100644
--- a/test/regress/regress0/datatypes/datatype13.cvc
+++ b/test/regress/regress0/datatypes/datatype13.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE enum = enum1
| enum2
diff --git a/test/regress/regress0/datatypes/datatype2.cvc b/test/regress/regress0/datatypes/datatype2.cvc
index 939dff197..64c84de45 100644
--- a/test/regress/regress0/datatypes/datatype2.cvc
+++ b/test/regress/regress0/datatypes/datatype2.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
diff --git a/test/regress/regress0/datatypes/datatype3.cvc b/test/regress/regress0/datatypes/datatype3.cvc
index fff1a5dd7..ce99edbb7 100644
--- a/test/regress/regress0/datatypes/datatype3.cvc
+++ b/test/regress/regress0/datatypes/datatype3.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
tree = node(left : tree, right : tree) | leaf
diff --git a/test/regress/regress0/datatypes/datatype4.cvc b/test/regress/regress0/datatypes/datatype4.cvc
index 217777bdf..83962f49a 100644
--- a/test/regress/regress0/datatypes/datatype4.cvc
+++ b/test/regress/regress0/datatypes/datatype4.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
TypeGeneric = generic
END;
diff --git a/test/regress/regress0/datatypes/empty_tuprec.cvc b/test/regress/regress0/datatypes/empty_tuprec.cvc
index 4f6320028..b6950845e 100644
--- a/test/regress/regress0/datatypes/empty_tuprec.cvc
+++ b/test/regress/regress0/datatypes/empty_tuprec.cvc
@@ -7,15 +7,15 @@ b1, b2 : [##]; % empty records (a unit type)
c1, c2 : [[]]; % 1-tuples of the empty tuple (a unit type)
d1, d2 : [#x:[[##]],y:[#z:[]#]#]; % more complicated records (still a unit type)
-% EXPECT: valid
+% EXPECT: entailed
QUERY a1 = a2;
-% EXPECT: valid
+% EXPECT: entailed
QUERY b1 = b2;
-% EXPECT: valid
+% EXPECT: entailed
QUERY c1 = c2;
-% EXPECT: valid
+% EXPECT: entailed
QUERY d1 = d2;
diff --git a/test/regress/regress0/datatypes/mutually-recursive.cvc b/test/regress/regress0/datatypes/mutually-recursive.cvc
index b86b647b5..5bd857b6e 100644
--- a/test/regress/regress0/datatypes/mutually-recursive.cvc
+++ b/test/regress/regress0/datatypes/mutually-recursive.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE nat = succ(pred : nat2) | zero,
nat2 = succ2(pred2 : nat) | zero2 END;
diff --git a/test/regress/regress0/datatypes/rec1.cvc b/test/regress/regress0/datatypes/rec1.cvc
index 79c9facda..b3e205985 100644
--- a/test/regress/regress0/datatypes/rec1.cvc
+++ b/test/regress/regress0/datatypes/rec1.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
c : BOOLEAN;
a17 : BOOLEAN = ((# _a := 2, _b := 2 #) = (
IF c THEN (# _a := 3, _b := 2 #)
diff --git a/test/regress/regress0/datatypes/rec2.cvc b/test/regress/regress0/datatypes/rec2.cvc
index 44d523a46..56864c088 100644
--- a/test/regress/regress0/datatypes/rec2.cvc
+++ b/test/regress/regress0/datatypes/rec2.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
c : BOOLEAN;
a16 : [# _a : INT, _b : INT #] = (
IF c THEN (# _a := 3, _b := 2 #)
diff --git a/test/regress/regress0/datatypes/rec4.cvc b/test/regress/regress0/datatypes/rec4.cvc
index 08a9988ef..f7f29755f 100644
--- a/test/regress/regress0/datatypes/rec4.cvc
+++ b/test/regress/regress0/datatypes/rec4.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
a : BOOLEAN;
a49 : BOOLEAN = (
IF a THEN (# _a := 1 #)
diff --git a/test/regress/regress0/datatypes/rewriter.cvc b/test/regress/regress0/datatypes/rewriter.cvc
index 18f8b3441..e9b7662a0 100644
--- a/test/regress/regress0/datatypes/rewriter.cvc
+++ b/test/regress/regress0/datatypes/rewriter.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% simple test for rewriter cases
diff --git a/test/regress/regress0/datatypes/tuple-record-bug.cvc b/test/regress/regress0/datatypes/tuple-record-bug.cvc
index 33c68dece..0e519a64f 100644
--- a/test/regress/regress0/datatypes/tuple-record-bug.cvc
+++ b/test/regress/regress0/datatypes/tuple-record-bug.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
Mem_0 : TYPE = ARRAY INT OF INT;
diff --git a/test/regress/regress0/datatypes/tuple.cvc b/test/regress/regress0/datatypes/tuple.cvc
index 366737525..00ab8d4db 100644
--- a/test/regress/regress0/datatypes/tuple.cvc
+++ b/test/regress/regress0/datatypes/tuple.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x: [REAL,INT,REAL] = ( 4/5, 9, 11/9 );
first_elem: REAL = x.0;
third_elem: REAL = x.2;
diff --git a/test/regress/regress0/datatypes/typed_v10l30054.cvc b/test/regress/regress0/datatypes/typed_v10l30054.cvc
index ee414ed65..72c23d888 100644
--- a/test/regress/regress0/datatypes/typed_v10l30054.cvc
+++ b/test/regress/regress0/datatypes/typed_v10l30054.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/typed_v1l80005.cvc b/test/regress/regress0/datatypes/typed_v1l80005.cvc
index 988646f21..95b1a935f 100644
--- a/test/regress/regress0/datatypes/typed_v1l80005.cvc
+++ b/test/regress/regress0/datatypes/typed_v1l80005.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/typed_v2l30079.cvc b/test/regress/regress0/datatypes/typed_v2l30079.cvc
index f32c9e551..2295d1518 100644
--- a/test/regress/regress0/datatypes/typed_v2l30079.cvc
+++ b/test/regress/regress0/datatypes/typed_v2l30079.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/typed_v3l20092.cvc b/test/regress/regress0/datatypes/typed_v3l20092.cvc
index c6260e233..e067852df 100644
--- a/test/regress/regress0/datatypes/typed_v3l20092.cvc
+++ b/test/regress/regress0/datatypes/typed_v3l20092.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/typed_v5l30069.cvc b/test/regress/regress0/datatypes/typed_v5l30069.cvc
index 05d0247cc..f980acc69 100644
--- a/test/regress/regress0/datatypes/typed_v5l30069.cvc
+++ b/test/regress/regress0/datatypes/typed_v5l30069.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/v10l40099.cvc b/test/regress/regress0/datatypes/v10l40099.cvc
index 7b2da4b65..257bf2ccc 100644
--- a/test/regress/regress0/datatypes/v10l40099.cvc
+++ b/test/regress/regress0/datatypes/v10l40099.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/v2l40025.cvc b/test/regress/regress0/datatypes/v2l40025.cvc
index fc466f300..d3411e12e 100644
--- a/test/regress/regress0/datatypes/v2l40025.cvc
+++ b/test/regress/regress0/datatypes/v2l40025.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/v3l60006.cvc b/test/regress/regress0/datatypes/v3l60006.cvc
index b7019e7ae..ea27672d5 100644
--- a/test/regress/regress0/datatypes/v3l60006.cvc
+++ b/test/regress/regress0/datatypes/v3l60006.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/v5l30058.cvc b/test/regress/regress0/datatypes/v5l30058.cvc
index be101b8fb..d3db742ae 100644
--- a/test/regress/regress0/datatypes/v5l30058.cvc
+++ b/test/regress/regress0/datatypes/v5l30058.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
diff --git a/test/regress/regress0/datatypes/wrong-sel-simp.cvc b/test/regress/regress0/datatypes/wrong-sel-simp.cvc
index b0dbdc46e..67be78912 100644
--- a/test/regress/regress0/datatypes/wrong-sel-simp.cvc
+++ b/test/regress/regress0/datatypes/wrong-sel-simp.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
nat = succ(pred : nat) | zero
END;
diff --git a/test/regress/regress0/fmf/bug-041417-set-options.cvc b/test/regress/regress0/fmf/bug-041417-set-options.cvc
index 16f59f78c..c4e9ba834 100644
--- a/test/regress/regress0/fmf/bug-041417-set-options.cvc
+++ b/test/regress/regress0/fmf/bug-041417-set-options.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
OPTION "finite-model-find";
OPTION "fmf-fun";
diff --git a/test/regress/regress0/let.cvc b/test/regress/regress0/let.cvc
index 996b09d39..d0f5c5e1f 100644
--- a/test/regress/regress0/let.cvc
+++ b/test/regress/regress0/let.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
U: TYPE;
a: U;
b: U;
diff --git a/test/regress/regress0/logops.01.cvc b/test/regress/regress0/logops.01.cvc
index 2c2ac2f79..305f2d396 100644
--- a/test/regress/regress0/logops.01.cvc
+++ b/test/regress/regress0/logops.01.cvc
@@ -1,3 +1,3 @@
a, b, c: BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY (a XOR b) <=> (NOT a AND b) OR (NOT b AND a);
diff --git a/test/regress/regress0/logops.02.cvc b/test/regress/regress0/logops.02.cvc
index 67415e95d..c74c11983 100644
--- a/test/regress/regress0/logops.02.cvc
+++ b/test/regress/regress0/logops.02.cvc
@@ -1,3 +1,3 @@
a, b, c: BOOLEAN;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY NOT c AND b;
diff --git a/test/regress/regress0/logops.03.cvc b/test/regress/regress0/logops.03.cvc
index 42298a8f4..1c86ce594 100644
--- a/test/regress/regress0/logops.03.cvc
+++ b/test/regress/regress0/logops.03.cvc
@@ -1,3 +1,3 @@
a, b, c: BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY (IF c THEN a ELSE b ENDIF) <=> ((c AND a) OR (NOT c AND b));
diff --git a/test/regress/regress0/logops.04.cvc b/test/regress/regress0/logops.04.cvc
index 89a9db320..254b0ed87 100644
--- a/test/regress/regress0/logops.04.cvc
+++ b/test/regress/regress0/logops.04.cvc
@@ -1,3 +1,3 @@
a, b, c: BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY (a => b) <=> (NOT a OR b);
diff --git a/test/regress/regress0/logops.05.cvc b/test/regress/regress0/logops.05.cvc
index 1ec94e5ae..2897dbc0c 100644
--- a/test/regress/regress0/logops.05.cvc
+++ b/test/regress/regress0/logops.05.cvc
@@ -1,4 +1,4 @@
a, b, c: BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY TRUE XOR FALSE;
diff --git a/test/regress/regress0/nl/ext-rew-aggr-test.smt2 b/test/regress/regress0/nl/ext-rew-aggr-test.smt2
index 47006622d..c540ecbe5 100644
--- a/test/regress/regress0/nl/ext-rew-aggr-test.smt2
+++ b/test/regress/regress0/nl/ext-rew-aggr-test.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --ext-rew-prep --ext-rew-prep-agg --no-new-prop
+; COMMAND-LINE: --ext-rew-prep --ext-rew-prep-agg --no-new-prop --nl-ext-tplanes
; EXPECT: sat
(set-info :smt-lib-version 2.6)
(set-logic QF_NIA)
diff --git a/test/regress/regress0/parser/choice.cvc b/test/regress/regress0/parser/choice.cvc
new file mode 100644
index 000000000..e0ebac051
--- /dev/null
+++ b/test/regress/regress0/parser/choice.cvc
@@ -0,0 +1,10 @@
+% EXPECT: sat
+
+a : INT;
+b : INT;
+c : INT;
+
+ASSERT (CHOICE(x: INT): x = a) = 1;
+ASSERT (CHOICE(x: INT): x = b) = 2;
+
+CHECKSAT; \ No newline at end of file
diff --git a/test/regress/regress0/parser/choice.smt2 b/test/regress/regress0/parser/choice.smt2
new file mode 100644
index 000000000..19763e222
--- /dev/null
+++ b/test/regress/regress0/parser/choice.smt2
@@ -0,0 +1,10 @@
+(set-logic ALL)
+(set-info :status sat)
+(declare-fun a () Int)
+(declare-fun b () Int)
+(declare-fun c () Int)
+(assert (= (choice ((x Int)) (= x a)) 1))
+(assert (= (choice ((x Int)) (= x b)) 2))
+;(assert (let ((x (choice ((x Int)) true))) (and (distinct a b x)(= x c))))
+(check-sat)
+
diff --git a/test/regress/regress0/precedence/and-not.cvc b/test/regress/regress0/precedence/and-not.cvc
index 5115a90c1..3ede8d211 100644
--- a/test/regress/regress0/precedence/and-not.cvc
+++ b/test/regress/regress0/precedence/and-not.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of AND and NOT.
A, B: BOOLEAN;
diff --git a/test/regress/regress0/precedence/and-xor.cvc b/test/regress/regress0/precedence/and-xor.cvc
index 879becbbf..ec69087d1 100644
--- a/test/regress/regress0/precedence/and-xor.cvc
+++ b/test/regress/regress0/precedence/and-xor.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of XOR and AND.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/bool-cmp.cvc b/test/regress/regress0/precedence/bool-cmp.cvc
index b8729e92a..4f81c86ad 100644
--- a/test/regress/regress0/precedence/bool-cmp.cvc
+++ b/test/regress/regress0/precedence/bool-cmp.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of comparisons and booleans
x , y, z: INT;
diff --git a/test/regress/regress0/precedence/cmp-plus.cvc b/test/regress/regress0/precedence/cmp-plus.cvc
index a7c07fe30..54ee7b8f8 100644
--- a/test/regress/regress0/precedence/cmp-plus.cvc
+++ b/test/regress/regress0/precedence/cmp-plus.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of comparisons and plus/minus
x, y, z: INT;
diff --git a/test/regress/regress0/precedence/eq-fun.cvc b/test/regress/regress0/precedence/eq-fun.cvc
index 9e581d514..af81ea10d 100644
--- a/test/regress/regress0/precedence/eq-fun.cvc
+++ b/test/regress/regress0/precedence/eq-fun.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of function application and =
T : TYPE;
diff --git a/test/regress/regress0/precedence/iff-assoc.cvc b/test/regress/regress0/precedence/iff-assoc.cvc
index 745cc7474..4643292b6 100644
--- a/test/regress/regress0/precedence/iff-assoc.cvc
+++ b/test/regress/regress0/precedence/iff-assoc.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right associativity of <=>
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/iff-implies.cvc b/test/regress/regress0/precedence/iff-implies.cvc
index 947433c88..24181487d 100644
--- a/test/regress/regress0/precedence/iff-implies.cvc
+++ b/test/regress/regress0/precedence/iff-implies.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of <=> and =>.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/implies-assoc.cvc b/test/regress/regress0/precedence/implies-assoc.cvc
index 1a7cef3b1..c6883c6ad 100644
--- a/test/regress/regress0/precedence/implies-assoc.cvc
+++ b/test/regress/regress0/precedence/implies-assoc.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right associativity of =>
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/implies-iff.cvc b/test/regress/regress0/precedence/implies-iff.cvc
index 3de26eb18..9ebed72d4 100644
--- a/test/regress/regress0/precedence/implies-iff.cvc
+++ b/test/regress/regress0/precedence/implies-iff.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of <=> and =>.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/implies-or.cvc b/test/regress/regress0/precedence/implies-or.cvc
index d724d33ef..883e7d4a1 100644
--- a/test/regress/regress0/precedence/implies-or.cvc
+++ b/test/regress/regress0/precedence/implies-or.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of => and OR.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/not-and.cvc b/test/regress/regress0/precedence/not-and.cvc
index fc671d7b5..579531ded 100644
--- a/test/regress/regress0/precedence/not-and.cvc
+++ b/test/regress/regress0/precedence/not-and.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of AND and NOT.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/not-eq.cvc b/test/regress/regress0/precedence/not-eq.cvc
index f658c127e..f8c7366be 100644
--- a/test/regress/regress0/precedence/not-eq.cvc
+++ b/test/regress/regress0/precedence/not-eq.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of = and NOT.
A, B: INT;
diff --git a/test/regress/regress0/precedence/or-implies.cvc b/test/regress/regress0/precedence/or-implies.cvc
index 209df8559..746f142e4 100644
--- a/test/regress/regress0/precedence/or-implies.cvc
+++ b/test/regress/regress0/precedence/or-implies.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of => and OR.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/or-xor.cvc b/test/regress/regress0/precedence/or-xor.cvc
index 2a25bac63..405cb68b7 100644
--- a/test/regress/regress0/precedence/or-xor.cvc
+++ b/test/regress/regress0/precedence/or-xor.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of OR and XOR.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/plus-mult.cvc b/test/regress/regress0/precedence/plus-mult.cvc
index 5d980f90d..57b9b99cf 100644
--- a/test/regress/regress0/precedence/plus-mult.cvc
+++ b/test/regress/regress0/precedence/plus-mult.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of plus/minus and mult/divide
a, b, c, d, e: INT;
diff --git a/test/regress/regress0/precedence/xor-and.cvc b/test/regress/regress0/precedence/xor-and.cvc
index 68896db10..08c939c5e 100644
--- a/test/regress/regress0/precedence/xor-and.cvc
+++ b/test/regress/regress0/precedence/xor-and.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of XOR and AND.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/xor-assoc.cvc b/test/regress/regress0/precedence/xor-assoc.cvc
index f31324a53..5f4646b1f 100644
--- a/test/regress/regress0/precedence/xor-assoc.cvc
+++ b/test/regress/regress0/precedence/xor-assoc.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for left associativity of XOR
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/precedence/xor-or.cvc b/test/regress/regress0/precedence/xor-or.cvc
index 757286764..87abc0e73 100644
--- a/test/regress/regress0/precedence/xor-or.cvc
+++ b/test/regress/regress0/precedence/xor-or.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
% Simple test for right precedence of OR and XOR.
A, B, C: BOOLEAN;
diff --git a/test/regress/regress0/preprocess/preprocess_00.cvc b/test/regress/regress0/preprocess/preprocess_00.cvc
index c86843535..2e51a42ad 100644
--- a/test/regress/regress0/preprocess/preprocess_00.cvc
+++ b/test/regress/regress0/preprocess/preprocess_00.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9: BOOLEAN;
diff --git a/test/regress/regress0/preprocess/preprocess_02.cvc b/test/regress/regress0/preprocess/preprocess_02.cvc
index e2c93a359..0f94103f6 100644
--- a/test/regress/regress0/preprocess/preprocess_02.cvc
+++ b/test/regress/regress0/preprocess/preprocess_02.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9: BOOLEAN;
diff --git a/test/regress/regress0/preprocess/preprocess_06.cvc b/test/regress/regress0/preprocess/preprocess_06.cvc
index 3e45c529a..abcc7a6ac 100644
--- a/test/regress/regress0/preprocess/preprocess_06.cvc
+++ b/test/regress/regress0/preprocess/preprocess_06.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
a0, a1, a2, a3, a4, a5: BOOLEAN;
diff --git a/test/regress/regress0/preprocess/preprocess_13.cvc b/test/regress/regress0/preprocess/preprocess_13.cvc
index 8b26c0d08..9a6cd797c 100644
--- a/test/regress/regress0/preprocess/preprocess_13.cvc
+++ b/test/regress/regress0/preprocess/preprocess_13.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9: BOOLEAN;
diff --git a/test/regress/regress0/printer/tuples_and_records.cvc b/test/regress/regress0/printer/tuples_and_records.cvc
index 267a316e8..966668002 100644
--- a/test/regress/regress0/printer/tuples_and_records.cvc
+++ b/test/regress/regress0/printer/tuples_and_records.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
% EXPECT: ((r.a, "active"))
% EXPECT: ((y.1, 9))
OPTION "produce-models";
diff --git a/test/regress/regress0/push-pop/bug233.cvc b/test/regress/regress0/push-pop/bug233.cvc
index 2b9eedcdb..1a6049329 100644
--- a/test/regress/regress0/push-pop/bug233.cvc
+++ b/test/regress/regress0/push-pop/bug233.cvc
@@ -3,9 +3,9 @@
a, b: BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY (a AND b) OR NOT (a AND b);
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY (a OR b);
diff --git a/test/regress/regress0/push-pop/incremental-subst-bug.cvc b/test/regress/regress0/push-pop/incremental-subst-bug.cvc
index 9b10ef843..657e74486 100644
--- a/test/regress/regress0/push-pop/incremental-subst-bug.cvc
+++ b/test/regress/regress0/push-pop/incremental-subst-bug.cvc
@@ -1,21 +1,21 @@
% COMMAND-LINE: --incremental
U : TYPE;
x, y : U;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY x = y;
ASSERT x = y;
-% EXPECT: valid
+% EXPECT: entailed
QUERY x = y;
PUSH;
z : U;
-% EXPECT: valid
+% EXPECT: entailed
QUERY x = y;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY x = z;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY z = x;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY z /= x;
POP;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY z /= x;
diff --git a/test/regress/regress0/quantifiers/cegqi-nl-simp.cvc b/test/regress/regress0/quantifiers/cegqi-nl-simp.cvc
index 63cf52fd6..d01d7b7d2 100644
--- a/test/regress/regress0/quantifiers/cegqi-nl-simp.cvc
+++ b/test/regress/regress0/quantifiers/cegqi-nl-simp.cvc
@@ -1,2 +1,2 @@
-% EXPECT: valid
+% EXPECT: entailed
QUERY FORALL (x:INT) : EXISTS (y:INT) : (x*y=x) ;
diff --git a/test/regress/regress0/sets/cvc-sample.cvc b/test/regress/regress0/sets/cvc-sample.cvc
index 6740faa8c..06d2b5049 100644
--- a/test/regress/regress0/sets/cvc-sample.cvc
+++ b/test/regress/regress0/sets/cvc-sample.cvc
@@ -4,7 +4,7 @@
% EXPECT: unsat
% EXPECT: unsat
% EXPECT: unsat
-% EXPECT: invalid
+% EXPECT: not_entailed
OPTION "incremental" true;
OPTION "logic" "ALL_SUPPORTED";
SetInt : TYPE = SET OF INT;
diff --git a/test/regress/regress0/simple.cvc b/test/regress/regress0/simple.cvc
index 83d0225bd..def48254e 100644
--- a/test/regress/regress0/simple.cvc
+++ b/test/regress/regress0/simple.cvc
@@ -3,5 +3,5 @@ ASSERT x1 OR NOT x0;
ASSERT x0 OR NOT x3;
ASSERT x3 OR x2;
ASSERT x1 AND NOT x1;
-% EXPECT: valid
+% EXPECT: entailed
QUERY x2;
diff --git a/test/regress/regress0/smallcnf.cvc b/test/regress/regress0/smallcnf.cvc
index bd732b4dc..dcb7c6f0d 100644
--- a/test/regress/regress0/smallcnf.cvc
+++ b/test/regress/regress0/smallcnf.cvc
@@ -4,6 +4,6 @@ ASSERT NOT a OR NOT b;
ASSERT c OR b OR a;
ASSERT b OR NOT a;
ASSERT a OR NOT b OR c;
-% EXPECT: invalid
+% EXPECT: not_entailed
QUERY FALSE;
diff --git a/test/regress/regress0/smtlib/issue4151.smt2 b/test/regress/regress0/smtlib/issue4151.smt2
new file mode 100644
index 000000000..629ec48b6
--- /dev/null
+++ b/test/regress/regress0/smtlib/issue4151.smt2
@@ -0,0 +1,13 @@
+; EXPECT: sat
+; EXPECT: unsat
+; EXPECT: (
+; EXPECT: )
+(set-logic ALL)
+(set-option :incremental true)
+(set-option :produce-unsat-assumptions true)
+(set-option :produce-unsat-cores true)
+(check-sat)
+(reset-assertions)
+(assert false)
+(check-sat)
+(get-unsat-core)
diff --git a/test/regress/regress0/smtlib/set-info-status.smt2 b/test/regress/regress0/smtlib/set-info-status.smt2
index 489d686b3..4bfa1766a 100644
--- a/test/regress/regress0/smtlib/set-info-status.smt2
+++ b/test/regress/regress0/smtlib/set-info-status.smt2
@@ -1,4 +1,4 @@
-; EXPECT: (error "Cannot get an unsat core unless immediately preceded by UNSAT/VALID response.")
+; EXPECT: (error "Cannot get an unsat core unless immediately preceded by UNSAT/ENTAILED response.")
; EXPECT: sat
; EXPECT: sat
; EXPECT: unsat
diff --git a/test/regress/regress0/strings/bug002.smt2 b/test/regress/regress0/strings/bug002.smt2
index fd60089fd..5bf21ebb9 100644
--- a/test/regress/regress0/strings/bug002.smt2
+++ b/test/regress/regress0/strings/bug002.smt2
@@ -4,7 +4,7 @@
(set-info :status sat)
; regex = [\*-,\t\*-\|](.{6,}()?)+
-(define-fun strinre ((?s String)) Bool (str.in.re ?s (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.union re.nostr (re.range "*" ",") (str.to.re "\t") (re.range "*" "|") ) (re.+ (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.loop re.allchar 6 ) (re.opt (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") ) ) ) ) ) ) ) ) ) )
+(define-fun strinre ((?s String)) Bool (str.in.re ?s (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.union re.nostr (re.range "*" ",") (str.to.re "\t") (re.range "*" "|") ) (re.+ (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") ((_ re.^ 6) re.allchar) (re.opt (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") ) ) ) ) ) ) ) ) ) )
(assert (not (strinre "6O\1\127\n?")))
(check-sat)
diff --git a/test/regress/regress0/strings/char-representations.smt2 b/test/regress/regress0/strings/char-representations.smt2
new file mode 100644
index 000000000..aaf119ab4
--- /dev/null
+++ b/test/regress/regress0/strings/char-representations.smt2
@@ -0,0 +1,22 @@
+; COMMAND-LINE: --lang=smt2.6.1
+; EXPECT: sat
+(set-logic SLIA)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+
+(assert (= x (_ char #x0D4)))
+(assert (= x "\u00d4"))
+
+
+(assert (= y (_ char #x1)))
+(assert (= y "\u0001"))
+
+(assert (= z (_ char #xAF)))
+(assert (= z (_ char #x0af)))
+(assert (= z "\u{af}"))
+(assert (= z "\u00af"))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/gen-esc-seq.smt2 b/test/regress/regress0/strings/gen-esc-seq.smt2
new file mode 100644
index 000000000..59f66046f
--- /dev/null
+++ b/test/regress/regress0/strings/gen-esc-seq.smt2
@@ -0,0 +1,9 @@
+; COMMAND-LINE: --produce-models --lang=smt2.6.1
+; EXPECT: sat
+; EXPECT: ((x "\u{5c}u1000"))
+(set-logic ALL)
+(set-info :status sat)
+(declare-const x String)
+(assert (= x (str.++ "\u" "1000")))
+(check-sat)
+(get-value (x))
diff --git a/test/regress/regress0/strings/loop-wrong-sem.smt2 b/test/regress/regress0/strings/loop-wrong-sem.smt2
new file mode 100644
index 000000000..d0dd3fcb2
--- /dev/null
+++ b/test/regress/regress0/strings/loop-wrong-sem.smt2
@@ -0,0 +1,4 @@
+(set-logic ALL)
+(set-info :status unsat)
+(assert (str.in.re "" ((_ re.loop 1 0) (str.to.re ""))))
+(check-sat)
diff --git a/test/regress/regress0/strings/model-code-point.smt2 b/test/regress/regress0/strings/model-code-point.smt2
new file mode 100644
index 000000000..1200ae704
--- /dev/null
+++ b/test/regress/regress0/strings/model-code-point.smt2
@@ -0,0 +1,13 @@
+; COMMAND-LINE: --lang=smt2.6.1 --produce-models
+; EXPECT: sat
+; EXPECT: ((x "\u{a}"))
+; EXPECT: ((y "\u{7f}"))
+(set-logic ALL)
+(set-info :status sat)
+(declare-fun x () String)
+(declare-fun y () String)
+(assert (= (str.to_code x) 10))
+(assert (= (str.to_code y) 127))
+(check-sat)
+(get-value (x))
+(get-value (y))
diff --git a/test/regress/regress0/strings/model-friendly.smt2 b/test/regress/regress0/strings/model-friendly.smt2
new file mode 100644
index 000000000..985ffaa62
--- /dev/null
+++ b/test/regress/regress0/strings/model-friendly.smt2
@@ -0,0 +1,9 @@
+; COMMAND-LINE: --lang=smt2.6.1 --produce-models
+; EXPECT: sat
+; EXPECT: ((x "AAAAA"))
+(set-logic ALL)
+(set-info :status sat)
+(declare-fun x () String)
+(assert (= (str.len x) 5))
+(check-sat)
+(get-value (x))
diff --git a/test/regress/regress0/strings/unicode-esc.smt2 b/test/regress/regress0/strings/unicode-esc.smt2
new file mode 100644
index 000000000..02b313d4a
--- /dev/null
+++ b/test/regress/regress0/strings/unicode-esc.smt2
@@ -0,0 +1,32 @@
+; COMMAND-LINE: --strings-exp --lang=smt2.6.1
+; EXPECT: sat
+(set-logic ALL)
+
+(assert (= "\u{14}" "\u0014"))
+(assert (= "\u{00}" "\u{0}"))
+(assert (= "\u0000" "\u{0}"))
+(assert (= (str.len "\u1234") 1))
+(assert (= (str.len "\u{1}") 1))
+(assert (= (str.len "\u{99}") 1))
+(assert (= (str.len "\u{779}") 1))
+(assert (= (str.len "\u{0779}") 1))
+(assert (= (str.len "\u{01779}") 1))
+(assert (= (str.len "\u{001779}") 10))
+(assert (= (str.len "\u{0vv79}") 9))
+(assert (= (str.len "\u{11\u1234}") 7))
+(assert (= (str.len "\u12345") 2))
+(assert (= (str.len "\uu") 3))
+(assert (= (str.len "\u{123}\u{567}") 2))
+(assert (= (str.len "\u{0017") 7))
+(assert (= (str.len "\\u00178") 3))
+(assert (= (str.len "2\u{}") 5))
+(assert (= (str.len "\uaaaa") 1))
+(assert (= (str.len "\uAAAA") 1))
+(assert (= (str.len "\u{0AbC}") 1))
+(assert (= (str.len "\u{E}") 1))
+(assert (= (str.len "\u{44444}") 9))
+(assert (= (str.len "\u") 2))
+(assert (= (str.len "\u001") 5))
+(assert (= (str.len "\u0001") 1))
+
+(check-sat)
diff --git a/test/regress/regress0/sygus/c100.sy b/test/regress/regress0/sygus/c100.sy
index ef124c953..994fb6de3 100644
--- a/test/regress/regress0/sygus/c100.sy
+++ b/test/regress/regress0/sygus/c100.sy
@@ -1,9 +1,10 @@
; EXPECT: unsat
-; COMMAND-LINE: --cegqi-si=all --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --sygus-out=status
(set-logic LIA)
(synth-fun constant ((x Int)) Int
+ ((Start Int))
((Start Int (0
2
3
@@ -15,4 +16,3 @@
(declare-var x Int)
(constraint (= (constant x) 100))
(check-synth)
-
diff --git a/test/regress/regress0/sygus/check-generic-red.sy b/test/regress/regress0/sygus/check-generic-red.sy
index e169e1a5c..d593a7d9e 100644
--- a/test/regress/regress0/sygus/check-generic-red.sy
+++ b/test/regress/regress0/sygus/check-generic-red.sy
@@ -1,8 +1,9 @@
; EXPECT: unsat
-; COMMAND-LINE: --cegqi-si=all --sygus-out=status --decision=justification
+; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --sygus-out=status --decision=justification
(set-logic LIA)
(synth-fun P ((x Int) (y Int)) Bool
+ ((Start Bool) (StartIntC Int) (StartInt Int))
((Start Bool ((and Start Start)
(not Start)
(<= StartInt StartIntC)
diff --git a/test/regress/regress0/sygus/const-var-test.sy b/test/regress/regress0/sygus/const-var-test.sy
index 305f5783a..31e88f523 100644
--- a/test/regress/regress0/sygus/const-var-test.sy
+++ b/test/regress/regress0/sygus/const-var-test.sy
@@ -1,9 +1,10 @@
; EXPECT: unsat
-; COMMAND-LINE: --cegqi-si=all --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --sygus-out=status
(set-logic LIA)
(synth-fun max2 ((x Int) (y Int)) Int
+ ((Start Int) (StartBool Bool))
((Start Int ((Variable Int)
(Constant Int)
(+ Start Start)
@@ -21,6 +22,4 @@
(constraint (= (max2 x y) (+ x y 500)))
-
(check-synth)
-
diff --git a/test/regress/regress0/sygus/sygus-uf.sy b/test/regress/regress0/sygus/sygus-uf.sy
index d506dd5b2..b08aa8929 100644
--- a/test/regress/regress0/sygus/sygus-uf.sy
+++ b/test/regress/regress0/sygus/sygus-uf.sy
@@ -1,10 +1,11 @@
-; COMMAND-LINE: --sygus-out=status --uf-ho
+; COMMAND-LINE: --lang=sygus2 --sygus-out=status --uf-ho
; EXPECT: unsat
-(set-logic UFLIA)
+(set-logic ALL)
-(declare-fun uf (Int) Int)
+(declare-var uf (-> Int Int))
(synth-fun f ((x Int) (y Int)) Bool
+ ((Start Bool) (IntExpr Int))
((Start Bool (true false
(<= IntExpr IntExpr)
(= IntExpr IntExpr)
diff --git a/test/regress/regress0/test11.cvc b/test/regress/regress0/test11.cvc
index 45052deeb..26dda442e 100644
--- a/test/regress/regress0/test11.cvc
+++ b/test/regress/regress0/test11.cvc
@@ -3,5 +3,5 @@ x, y : BOOLEAN;
ASSERT (x OR y);
ASSERT NOT (x OR y);
-% EXPECT: valid
+% EXPECT: entailed
QUERY FALSE;
diff --git a/test/regress/regress0/test9.cvc b/test/regress/regress0/test9.cvc
index bfe1a3285..7872f5a1a 100644
--- a/test/regress/regress0/test9.cvc
+++ b/test/regress/regress0/test9.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
P,Q:BOOLEAN;
ASSERT (P OR Q);
QUERY (P OR Q);
diff --git a/test/regress/regress0/uf/simple.01.cvc b/test/regress/regress0/uf/simple.01.cvc
index 42b99cc44..6b0f93324 100644
--- a/test/regress/regress0/uf/simple.01.cvc
+++ b/test/regress/regress0/uf/simple.01.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
A: TYPE;
B: TYPE;
x, y: A;
diff --git a/test/regress/regress0/uf/simple.02.cvc b/test/regress/regress0/uf/simple.02.cvc
index 1dd96fd1c..2bd0b1e1e 100644
--- a/test/regress/regress0/uf/simple.02.cvc
+++ b/test/regress/regress0/uf/simple.02.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
A: TYPE;
B: TYPE;
x, y: A;
diff --git a/test/regress/regress0/uf/simple.03.cvc b/test/regress/regress0/uf/simple.03.cvc
index cc1721ca6..15fe5907c 100644
--- a/test/regress/regress0/uf/simple.03.cvc
+++ b/test/regress/regress0/uf/simple.03.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
A: TYPE;
B: TYPE;
x, y: A;
diff --git a/test/regress/regress0/uf/simple.04.cvc b/test/regress/regress0/uf/simple.04.cvc
index 66223ca7b..0fc52bcca 100644
--- a/test/regress/regress0/uf/simple.04.cvc
+++ b/test/regress/regress0/uf/simple.04.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
A: TYPE;
B: TYPE;
x, y: A;
diff --git a/test/regress/regress0/uf20-03.cvc b/test/regress/regress0/uf20-03.cvc
index 9de754284..b25d8a471 100644
--- a/test/regress/regress0/uf20-03.cvc
+++ b/test/regress/regress0/uf20-03.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x_1 : BOOLEAN;
x_2 : BOOLEAN;
x_3 : BOOLEAN;
diff --git a/test/regress/regress0/wiki.01.cvc b/test/regress/regress0/wiki.01.cvc
index fb38fab65..1516503ff 100644
--- a/test/regress/regress0/wiki.01.cvc
+++ b/test/regress/regress0/wiki.01.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR (b OR c) <=> (a OR b) OR c;
diff --git a/test/regress/regress0/wiki.02.cvc b/test/regress/regress0/wiki.02.cvc
index 93d555c96..ebeadee14 100644
--- a/test/regress/regress0/wiki.02.cvc
+++ b/test/regress/regress0/wiki.02.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND (b AND c) <=> (a AND b) AND c;
diff --git a/test/regress/regress0/wiki.03.cvc b/test/regress/regress0/wiki.03.cvc
index 08b049c17..ca0e6a8d1 100644
--- a/test/regress/regress0/wiki.03.cvc
+++ b/test/regress/regress0/wiki.03.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR b <=> b OR a;
diff --git a/test/regress/regress0/wiki.04.cvc b/test/regress/regress0/wiki.04.cvc
index b88de6144..75fe17238 100644
--- a/test/regress/regress0/wiki.04.cvc
+++ b/test/regress/regress0/wiki.04.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND b <=> b AND a;
diff --git a/test/regress/regress0/wiki.05.cvc b/test/regress/regress0/wiki.05.cvc
index 0fe647f7b..2f87e4ca0 100644
--- a/test/regress/regress0/wiki.05.cvc
+++ b/test/regress/regress0/wiki.05.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR (a AND b) <=> a;
diff --git a/test/regress/regress0/wiki.06.cvc b/test/regress/regress0/wiki.06.cvc
index 1d466a86e..a4075bda3 100644
--- a/test/regress/regress0/wiki.06.cvc
+++ b/test/regress/regress0/wiki.06.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND (a OR b) <=> a;
diff --git a/test/regress/regress0/wiki.07.cvc b/test/regress/regress0/wiki.07.cvc
index 146d92832..3b4527bdc 100644
--- a/test/regress/regress0/wiki.07.cvc
+++ b/test/regress/regress0/wiki.07.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR (b AND c) <=> (a OR b) AND (a OR c);
diff --git a/test/regress/regress0/wiki.08.cvc b/test/regress/regress0/wiki.08.cvc
index e9c7d3fa3..e15a21412 100644
--- a/test/regress/regress0/wiki.08.cvc
+++ b/test/regress/regress0/wiki.08.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND (b OR c) <=> (a AND b) OR (a AND c);
diff --git a/test/regress/regress0/wiki.09.cvc b/test/regress/regress0/wiki.09.cvc
index 478be2db9..5bc5faca5 100644
--- a/test/regress/regress0/wiki.09.cvc
+++ b/test/regress/regress0/wiki.09.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR NOT a;
diff --git a/test/regress/regress0/wiki.10.cvc b/test/regress/regress0/wiki.10.cvc
index 226a3da82..613022e84 100644
--- a/test/regress/regress0/wiki.10.cvc
+++ b/test/regress/regress0/wiki.10.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND NOT a <=> FALSE;
diff --git a/test/regress/regress0/wiki.11.cvc b/test/regress/regress0/wiki.11.cvc
index d615fef3b..8debef9cd 100644
--- a/test/regress/regress0/wiki.11.cvc
+++ b/test/regress/regress0/wiki.11.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR a <=> a;
diff --git a/test/regress/regress0/wiki.12.cvc b/test/regress/regress0/wiki.12.cvc
index 209e512a6..2274fc78e 100644
--- a/test/regress/regress0/wiki.12.cvc
+++ b/test/regress/regress0/wiki.12.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND a <=> a;
diff --git a/test/regress/regress0/wiki.13.cvc b/test/regress/regress0/wiki.13.cvc
index 2cc69f048..80b95802d 100644
--- a/test/regress/regress0/wiki.13.cvc
+++ b/test/regress/regress0/wiki.13.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR FALSE <=> a;
diff --git a/test/regress/regress0/wiki.14.cvc b/test/regress/regress0/wiki.14.cvc
index 5a6c16248..7b8a14edb 100644
--- a/test/regress/regress0/wiki.14.cvc
+++ b/test/regress/regress0/wiki.14.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND TRUE <=> a;
diff --git a/test/regress/regress0/wiki.15.cvc b/test/regress/regress0/wiki.15.cvc
index 6dc84f679..dfb4f13fc 100644
--- a/test/regress/regress0/wiki.15.cvc
+++ b/test/regress/regress0/wiki.15.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a OR TRUE <=> TRUE;
diff --git a/test/regress/regress0/wiki.16.cvc b/test/regress/regress0/wiki.16.cvc
index 6b2bf4113..9c69baa52 100644
--- a/test/regress/regress0/wiki.16.cvc
+++ b/test/regress/regress0/wiki.16.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY a AND FALSE <=> FALSE;
diff --git a/test/regress/regress0/wiki.17.cvc b/test/regress/regress0/wiki.17.cvc
index 7c6701acc..c58160bb9 100644
--- a/test/regress/regress0/wiki.17.cvc
+++ b/test/regress/regress0/wiki.17.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY NOT FALSE <=> TRUE;
diff --git a/test/regress/regress0/wiki.18.cvc b/test/regress/regress0/wiki.18.cvc
index 7c1b1b8e4..17773b899 100644
--- a/test/regress/regress0/wiki.18.cvc
+++ b/test/regress/regress0/wiki.18.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY NOT TRUE <=> FALSE;
diff --git a/test/regress/regress0/wiki.19.cvc b/test/regress/regress0/wiki.19.cvc
index d5812b5ea..46b6fc02e 100644
--- a/test/regress/regress0/wiki.19.cvc
+++ b/test/regress/regress0/wiki.19.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY NOT (a OR b) <=> NOT a AND NOT b;
diff --git a/test/regress/regress0/wiki.20.cvc b/test/regress/regress0/wiki.20.cvc
index 8d2570620..42e114010 100644
--- a/test/regress/regress0/wiki.20.cvc
+++ b/test/regress/regress0/wiki.20.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY NOT (a AND b) <=> NOT a OR NOT b;
diff --git a/test/regress/regress0/wiki.21.cvc b/test/regress/regress0/wiki.21.cvc
index d65cbcf65..bcc69beea 100644
--- a/test/regress/regress0/wiki.21.cvc
+++ b/test/regress/regress0/wiki.21.cvc
@@ -1,4 +1,4 @@
a, b, c : BOOLEAN;
-% EXPECT: valid
+% EXPECT: entailed
QUERY NOT NOT a <=> a;
diff --git a/test/regress/regress1/arith/arith-brab-test.smt2 b/test/regress/regress1/arith/arith-brab-test.smt2
new file mode 100644
index 000000000..7856ae0e6
--- /dev/null
+++ b/test/regress/regress1/arith/arith-brab-test.smt2
@@ -0,0 +1,23 @@
+; COMMAND-LINE: --arith-brab
+; COMMAND-LINE: --no-arith-brab
+; EXPECT: sat
+(set-logic ALL)
+
+(declare-fun x1 () Real)
+(declare-fun y1 () Real)
+(declare-fun m1 () Real)
+(declare-fun b1 () Real)
+
+(declare-fun x () Int)
+(declare-fun y () Int)
+
+(assert (= y1 (+ b1 (* m1 x1))))
+(assert (= x1 (/ m1 (- y1 b1))))
+(assert (= b1 1.25))
+(assert (= m1 (/ 1 3)))
+
+(assert (and (> x x1) (> y y1)))
+
+(check-sat)
+(exit)
+
diff --git a/test/regress/regress1/arith/arith-int-001.cvc b/test/regress/regress1/arith/arith-int-001.cvc
index 03ed1a6ae..3fd528c11 100644
--- a/test/regress/regress1/arith/arith-int-001.cvc
+++ b/test/regress/regress1/arith/arith-int-001.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-23 * x0) + (-23 * x1) + (5 * x2) + (-17 * x3) = 7 ;
ASSERT (-14 * x0) + (-14 * x1) + (19 * x2) + (-24 * x3) = 29 ;
diff --git a/test/regress/regress1/arith/arith-int-002.cvc b/test/regress/regress1/arith/arith-int-002.cvc
index 849daba79..6cc4b2c5e 100644
--- a/test/regress/regress1/arith/arith-int-002.cvc
+++ b/test/regress/regress1/arith/arith-int-002.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (17 * x0) + (-23 * x1) + (2 * x2) + (-19 * x3) = -18 ;
ASSERT (25 * x0) + (23 * x1) + (21 * x2) + (20 * x3) = 2 ;
diff --git a/test/regress/regress1/arith/arith-int-003.cvc b/test/regress/regress1/arith/arith-int-003.cvc
index 9c060c469..f294babe6 100644
--- a/test/regress/regress1/arith/arith-int-003.cvc
+++ b/test/regress/regress1/arith/arith-int-003.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (17 * x0) + (-7 * x1) + (15 * x2) + (21 * x3) = 19 ;
ASSERT (6 * x0) + (-24 * x1) + (25 * x2) + (-18 * x3) > -25 ;
diff --git a/test/regress/regress1/arith/arith-int-004.cvc b/test/regress/regress1/arith/arith-int-004.cvc
index 314b76d18..15b060d92 100644
--- a/test/regress/regress1/arith/arith-int-004.cvc
+++ b/test/regress/regress1/arith/arith-int-004.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (12 * x0) + (-25 * x1) + (21 * x2) + (7 * x3) < 27 ;
diff --git a/test/regress/regress1/arith/arith-int-005.cvc b/test/regress/regress1/arith/arith-int-005.cvc
index 9b9776ad3..3701d60b4 100644
--- a/test/regress/regress1/arith/arith-int-005.cvc
+++ b/test/regress/regress1/arith/arith-int-005.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (13 * x0) + (0 * x1) + (6 * x2) + (-30 * x3) = -16 ;
ASSERT (-4 * x0) + (-8 * x1) + (14 * x2) + (-8 * x3) = -11 ;
diff --git a/test/regress/regress1/arith/arith-int-006.cvc b/test/regress/regress1/arith/arith-int-006.cvc
index 999b4a5b4..53a80310a 100644
--- a/test/regress/regress1/arith/arith-int-006.cvc
+++ b/test/regress/regress1/arith/arith-int-006.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-7 * x0) + (-28 * x1) + (8 * x2) + (29 * x3) = -18 ;
ASSERT (11 * x0) + (2 * x1) + (4 * x2) + (23 * x3) = 6 ;
diff --git a/test/regress/regress1/arith/arith-int-007.cvc b/test/regress/regress1/arith/arith-int-007.cvc
index 4cb4d88ef..c0732e2b2 100644
--- a/test/regress/regress1/arith/arith-int-007.cvc
+++ b/test/regress/regress1/arith/arith-int-007.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-19 * x0) + (17 * x1) + (30 * x2) + (-31 * x3) <= -20 ;
ASSERT (-3 * x0) + (16 * x1) + (20 * x2) + (-25 * x3) < 28 ;
diff --git a/test/regress/regress1/arith/arith-int-008.cvc b/test/regress/regress1/arith/arith-int-008.cvc
index 1ae22c993..1810d6f28 100644
--- a/test/regress/regress1/arith/arith-int-008.cvc
+++ b/test/regress/regress1/arith/arith-int-008.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-12 * x0) + (-15 * x1) + (-31 * x2) + (17 * x3) = -16 ;
ASSERT (11 * x0) + (-5 * x1) + (-8 * x2) + (-17 * x3) > -4 ;
diff --git a/test/regress/regress1/arith/arith-int-009.cvc b/test/regress/regress1/arith/arith-int-009.cvc
index 9bd7a2ce4..14b26da6c 100644
--- a/test/regress/regress1/arith/arith-int-009.cvc
+++ b/test/regress/regress1/arith/arith-int-009.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-16 * x0) + (-21 * x1) + (32 * x2) + (32 * x3) = -19 ;
ASSERT (-10 * x0) + (-21 * x1) + (13 * x2) + (-7 * x3) = 2 ;
diff --git a/test/regress/regress1/arith/arith-int-010.cvc b/test/regress/regress1/arith/arith-int-010.cvc
index 4ac85a984..aa649ba4a 100644
--- a/test/regress/regress1/arith/arith-int-010.cvc
+++ b/test/regress/regress1/arith/arith-int-010.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (19 * x0) + (-2 * x1) + (-29 * x2) + (-24 * x3) = 3 ;
ASSERT (3 * x0) + (11 * x1) + (-14 * x2) + (6 * x3) = 4 ;
diff --git a/test/regress/regress1/arith/arith-int-011.cvc b/test/regress/regress1/arith/arith-int-011.cvc
index bd2fa2a0d..7de68533f 100644
--- a/test/regress/regress1/arith/arith-int-011.cvc
+++ b/test/regress/regress1/arith/arith-int-011.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (13 * x0) + (-1 * x1) + (11 * x2) + (10 * x3) = 9 ;
ASSERT (-7 * x0) + (3 * x1) + (-22 * x2) + (16 * x3) >= 9;
diff --git a/test/regress/regress1/arith/arith-int-012.cvc b/test/regress/regress1/arith/arith-int-012.cvc
index 11b0dab27..10922dd89 100644
--- a/test/regress/regress1/arith/arith-int-012.cvc
+++ b/test/regress/regress1/arith/arith-int-012.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (18 * x0) + (32 * x1) + (-11 * x2) + (18 * x3) < -25 ;
ASSERT (-31 * x0) + (16 * x1) + (24 * x2) + (9 * x3) >= -24;
diff --git a/test/regress/regress1/arith/arith-int-013.cvc b/test/regress/regress1/arith/arith-int-013.cvc
index 329251cae..8a1f76add 100644
--- a/test/regress/regress1/arith/arith-int-013.cvc
+++ b/test/regress/regress1/arith/arith-int-013.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-22 * x0) + (-14 * x1) + (4 * x2) + (-12 * x3) > 25 ;
ASSERT (14 * x0) + (11 * x1) + (32 * x2) + (-8 * x3) >= 2;
diff --git a/test/regress/regress1/arith/arith-int-016.cvc b/test/regress/regress1/arith/arith-int-016.cvc
index 6774dd2d1..951650461 100644
--- a/test/regress/regress1/arith/arith-int-016.cvc
+++ b/test/regress/regress1/arith/arith-int-016.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-13 * x0) + (-4 * x1) + (-20 * x2) + (-26 * x3) = 2 ;
ASSERT (13 * x0) + (13 * x1) + (-14 * x2) + (26 * x3) = -8 ;
diff --git a/test/regress/regress1/arith/arith-int-017.cvc b/test/regress/regress1/arith/arith-int-017.cvc
index e9a06125a..48287249f 100644
--- a/test/regress/regress1/arith/arith-int-017.cvc
+++ b/test/regress/regress1/arith/arith-int-017.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (23 * x0) + (-4 * x1) + (-26 * x2) + (-1 * x3) = 10 ;
ASSERT (15 * x0) + (31 * x1) + (31 * x2) + (31 * x3) = 13 ;
diff --git a/test/regress/regress1/arith/arith-int-018.cvc b/test/regress/regress1/arith/arith-int-018.cvc
index 4cb97b77e..cae6fed72 100644
--- a/test/regress/regress1/arith/arith-int-018.cvc
+++ b/test/regress/regress1/arith/arith-int-018.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-11 * x0) + (-26 * x1) + (9 * x2) + (32 * x3) = -11 ;
ASSERT (-5 * x0) + (-11 * x1) + (-10 * x2) + (-31 * x3) = -23 ;
diff --git a/test/regress/regress1/arith/arith-int-019.cvc b/test/regress/regress1/arith/arith-int-019.cvc
index cf9ae2d70..a26bbac01 100644
--- a/test/regress/regress1/arith/arith-int-019.cvc
+++ b/test/regress/regress1/arith/arith-int-019.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (25 * x0) + (6 * x1) + (-30 * x2) + (29 * x3) = -5 ;
ASSERT (14 * x0) + (16 * x1) + (24 * x2) + (-7 * x3) <= 31 ;
diff --git a/test/regress/regress1/arith/arith-int-020.cvc b/test/regress/regress1/arith/arith-int-020.cvc
index 07a827465..c1416b38f 100644
--- a/test/regress/regress1/arith/arith-int-020.cvc
+++ b/test/regress/regress1/arith/arith-int-020.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-32 * x0) + (31 * x1) + (-32 * x2) + (-21 * x3) = 5 ;
ASSERT (32 * x0) + (5 * x1) + (23 * x2) + (-16 * x3) = 8 ;
diff --git a/test/regress/regress1/arith/arith-int-022.cvc b/test/regress/regress1/arith/arith-int-022.cvc
index 584348da4..4612f72c9 100644
--- a/test/regress/regress1/arith/arith-int-022.cvc
+++ b/test/regress/regress1/arith/arith-int-022.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-24 * x0) + (25 * x1) + (-28 * x2) + (31 * x3) > 18;
QUERY FALSE;
diff --git a/test/regress/regress1/arith/arith-int-024.cvc b/test/regress/regress1/arith/arith-int-024.cvc
index f57136dd1..73ae7c4ad 100644
--- a/test/regress/regress1/arith/arith-int-024.cvc
+++ b/test/regress/regress1/arith/arith-int-024.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (4 * x0) + (8 * x1) + (27 * x2) + (-12 * x3) = -5;
QUERY FALSE;
diff --git a/test/regress/regress1/arith/arith-int-026.cvc b/test/regress/regress1/arith/arith-int-026.cvc
index 9e69aa2d1..52f2478e0 100644
--- a/test/regress/regress1/arith/arith-int-026.cvc
+++ b/test/regress/regress1/arith/arith-int-026.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (22 * x0) + (25 * x1) + (1 * x2) + (-11 * x3) = 19 ;
ASSERT (-10 * x0) + (-27 * x1) + (6 * x2) + (6 * x3) = 28 ;
diff --git a/test/regress/regress1/arith/arith-int-027.cvc b/test/regress/regress1/arith/arith-int-027.cvc
index b45622fea..6c38642d2 100644
--- a/test/regress/regress1/arith/arith-int-027.cvc
+++ b/test/regress/regress1/arith/arith-int-027.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (17 * x0) + (29 * x1) + (-11 * x2) + (24 * x3) = 13 ;
ASSERT (16 * x0) + (-20 * x1) + (-5 * x2) + (12 * x3) = 13 ;
diff --git a/test/regress/regress1/arith/arith-int-028.cvc b/test/regress/regress1/arith/arith-int-028.cvc
index 61fee4203..7e8b78893 100644
--- a/test/regress/regress1/arith/arith-int-028.cvc
+++ b/test/regress/regress1/arith/arith-int-028.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-31 * x0) + (-5 * x1) + (-28 * x2) + (16 * x3) = 10 ;
ASSERT (3 * x0) + (-20 * x1) + (-11 * x2) + (-2 * x3) = 25 ;
diff --git a/test/regress/regress1/arith/arith-int-029.cvc b/test/regress/regress1/arith/arith-int-029.cvc
index ee49bbb68..ba49219d8 100644
--- a/test/regress/regress1/arith/arith-int-029.cvc
+++ b/test/regress/regress1/arith/arith-int-029.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-29 * x0) + (-17 * x1) + (11 * x2) + (1 * x3) = -15 ;
ASSERT (-13 * x0) + (1 * x1) + (-6 * x2) + (-15 * x3) = 32 ;
diff --git a/test/regress/regress1/arith/arith-int-030.cvc b/test/regress/regress1/arith/arith-int-030.cvc
index 70b6a3785..a6348b107 100644
--- a/test/regress/regress1/arith/arith-int-030.cvc
+++ b/test/regress/regress1/arith/arith-int-030.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-13 * x0) + (26 * x1) + (-11 * x2) + (17 * x3) = 17 ;
ASSERT (-15 * x0) + (2 * x1) + (-9 * x2) + (17 * x3) = -11 ;
diff --git a/test/regress/regress1/arith/arith-int-031.cvc b/test/regress/regress1/arith/arith-int-031.cvc
index 86242f7aa..056ab622e 100644
--- a/test/regress/regress1/arith/arith-int-031.cvc
+++ b/test/regress/regress1/arith/arith-int-031.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-21 * x0) + (-24 * x1) + (-31 * x2) + (12 * x3) = -10 ;
ASSERT (-4 * x0) + (22 * x1) + (9 * x2) + (17 * x3) > -20 ;
diff --git a/test/regress/regress1/arith/arith-int-032.cvc b/test/regress/regress1/arith/arith-int-032.cvc
index 1ee4c9844..08c29108e 100644
--- a/test/regress/regress1/arith/arith-int-032.cvc
+++ b/test/regress/regress1/arith/arith-int-032.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (4 * x0) + (-29 * x1) + (-9 * x2) + (9 * x3) = 8 ;
ASSERT (-26 * x0) + (-26 * x1) + (26 * x2) + (-18 * x3) = -20 ;
diff --git a/test/regress/regress1/arith/arith-int-033.cvc b/test/regress/regress1/arith/arith-int-033.cvc
index 599ba4e9a..8259a7725 100644
--- a/test/regress/regress1/arith/arith-int-033.cvc
+++ b/test/regress/regress1/arith/arith-int-033.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-14 * x0) + (16 * x1) + (-16 * x2) + (0 * x3) = -8 ;
ASSERT (3 * x0) + (-20 * x1) + (-12 * x2) + (-3 * x3) = -7 ;
diff --git a/test/regress/regress1/arith/arith-int-034.cvc b/test/regress/regress1/arith/arith-int-034.cvc
index ec615a785..2b5ae4f4f 100644
--- a/test/regress/regress1/arith/arith-int-034.cvc
+++ b/test/regress/regress1/arith/arith-int-034.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-20 * x0) + (-5 * x1) + (30 * x2) + (-24 * x3) = 12 ;
ASSERT (24 * x0) + (27 * x1) + (18 * x2) + (-5 * x3) = -16 ;
diff --git a/test/regress/regress1/arith/arith-int-035.cvc b/test/regress/regress1/arith/arith-int-035.cvc
index e7dee2484..1bad259e2 100644
--- a/test/regress/regress1/arith/arith-int-035.cvc
+++ b/test/regress/regress1/arith/arith-int-035.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-3 * x0) + (2 * x1) + (17 * x2) + (-4 * x3) = -17 ;
ASSERT (5 * x0) + (-4 * x1) + (22 * x2) + (14 * x3) = -15 ;
diff --git a/test/regress/regress1/arith/arith-int-036.cvc b/test/regress/regress1/arith/arith-int-036.cvc
index 9594f9586..0eb783815 100644
--- a/test/regress/regress1/arith/arith-int-036.cvc
+++ b/test/regress/regress1/arith/arith-int-036.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-9 * x0) + (-21 * x1) + (-25 * x2) + (-1 * x3) = -11 ;
ASSERT (31 * x0) + (-18 * x1) + (5 * x2) + (-11 * x3) = 10 ;
diff --git a/test/regress/regress1/arith/arith-int-037.cvc b/test/regress/regress1/arith/arith-int-037.cvc
index 4d4422d3f..c3ed60011 100644
--- a/test/regress/regress1/arith/arith-int-037.cvc
+++ b/test/regress/regress1/arith/arith-int-037.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (12 * x0) + (14 * x1) + (-22 * x2) + (-6 * x3) = 29 ;
ASSERT (-9 * x0) + (14 * x1) + (-23 * x2) + (-31 * x3) = 4 ;
diff --git a/test/regress/regress1/arith/arith-int-038.cvc b/test/regress/regress1/arith/arith-int-038.cvc
index 476133b24..52ac2b1e3 100644
--- a/test/regress/regress1/arith/arith-int-038.cvc
+++ b/test/regress/regress1/arith/arith-int-038.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-24 * x0) + (25 * x1) + (28 * x2) + (-31 * x3) = -1 ;
ASSERT (29 * x0) + (17 * x1) + (-2 * x2) + (-6 * x3) <= 4 ;
diff --git a/test/regress/regress1/arith/arith-int-039.cvc b/test/regress/regress1/arith/arith-int-039.cvc
index 9e9235ae8..cecb7f085 100644
--- a/test/regress/regress1/arith/arith-int-039.cvc
+++ b/test/regress/regress1/arith/arith-int-039.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (22 * x0) + (21 * x1) + (-18 * x2) + (21 * x3) = 30 ;
ASSERT (-31 * x0) + (22 * x1) + (-20 * x2) + (18 * x3) = -32 ;
diff --git a/test/regress/regress1/arith/arith-int-040.cvc b/test/regress/regress1/arith/arith-int-040.cvc
index 68502349f..f2dff7796 100644
--- a/test/regress/regress1/arith/arith-int-040.cvc
+++ b/test/regress/regress1/arith/arith-int-040.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-1 * x0) + (-24 * x1) + (3 * x2) + (-8 * x3) > -5 ;
ASSERT (29 * x0) + (17 * x1) + (-26 * x2) + (20 * x3) > 11 ;
diff --git a/test/regress/regress1/arith/arith-int-041.cvc b/test/regress/regress1/arith/arith-int-041.cvc
index a0c2dc0f9..9df03a9bd 100644
--- a/test/regress/regress1/arith/arith-int-041.cvc
+++ b/test/regress/regress1/arith/arith-int-041.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-31 * x0) + (8 * x1) + (16 * x2) + (5 * x3) >= 1 ;
ASSERT (-30 * x0) + (13 * x1) + (-17 * x2) + (13 * x3) < -24 ;
diff --git a/test/regress/regress1/arith/arith-int-043.cvc b/test/regress/regress1/arith/arith-int-043.cvc
index 7efea85e5..7a2d6d6af 100644
--- a/test/regress/regress1/arith/arith-int-043.cvc
+++ b/test/regress/regress1/arith/arith-int-043.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-21 * x0) + (-23 * x1) + (29 * x2) + (-4 * x3) = 25 ;
ASSERT (20 * x0) + (-19 * x1) + (3 * x2) + (-1 * x3) <= -8 ;
diff --git a/test/regress/regress1/arith/arith-int-044.cvc b/test/regress/regress1/arith/arith-int-044.cvc
index f933b014b..649532a4b 100644
--- a/test/regress/regress1/arith/arith-int-044.cvc
+++ b/test/regress/regress1/arith/arith-int-044.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
%%%% down from 24, up from 6, up from 39
x0, x1, x2, x3 : INT;
ASSERT (-30 * x0) + (18 * x1) + (17 * x2) + (3 * x3) = 0;
diff --git a/test/regress/regress1/arith/arith-int-045.cvc b/test/regress/regress1/arith/arith-int-045.cvc
index ca1a12ba6..2c552c915 100644
--- a/test/regress/regress1/arith/arith-int-045.cvc
+++ b/test/regress/regress1/arith/arith-int-045.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-22 * x0) + (-5 * x1) + (-5 * x2) + (25 * x3) = 22 ;
ASSERT (2 * x0) + (-25 * x1) + (4 * x2) + (-21 * x3) >= 0 ;
diff --git a/test/regress/regress1/arith/arith-int-046.cvc b/test/regress/regress1/arith/arith-int-046.cvc
index d4d206c6e..acf4dc9a9 100644
--- a/test/regress/regress1/arith/arith-int-046.cvc
+++ b/test/regress/regress1/arith/arith-int-046.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (2 * x0) + (-6 * x1) + (14 * x2) + (-24 * x3) > 4 ;
ASSERT (-13 * x0) + (-2 * x1) + (-9 * x2) + (-7 * x3) >= 29 ;
diff --git a/test/regress/regress1/arith/arith-int-047.cvc b/test/regress/regress1/arith/arith-int-047.cvc
index 0763e5dc3..bb1225b9d 100644
--- a/test/regress/regress1/arith/arith-int-047.cvc
+++ b/test/regress/regress1/arith/arith-int-047.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-14 * x0) + (27 * x1) + (10 * x2) + (1 * x3) = 10;
ASSERT (-29 * x0) + (-26 * x1) + (-16 * x2) + (17 * x3) >= 16 ;
diff --git a/test/regress/regress1/arith/arith-int-048.cvc b/test/regress/regress1/arith/arith-int-048.cvc
index e7c05332d..ccc84f389 100644
--- a/test/regress/regress1/arith/arith-int-048.cvc
+++ b/test/regress/regress1/arith/arith-int-048.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-13 * x0) + (-11 * x1) + (-14 * x2) + (21 * x3) = 6 ;
ASSERT (7 * x0) + (5 * x1) + (13 * x2) + (21 * x3) <= 27 ;
diff --git a/test/regress/regress1/arith/arith-int-049.cvc b/test/regress/regress1/arith/arith-int-049.cvc
index 8eabc78a8..72e3b7f31 100644
--- a/test/regress/regress1/arith/arith-int-049.cvc
+++ b/test/regress/regress1/arith/arith-int-049.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-15 * x0) + (-20 * x1) + (-32 * x2) + (-16 * x3) = -19 ;
ASSERT (24 * x0) + (23 * x1) + (22 * x2) + (30 * x3) >= 19 ;
diff --git a/test/regress/regress1/arith/arith-int-050.cvc b/test/regress/regress1/arith/arith-int-050.cvc
index f0ba939b7..21dbfe09a 100644
--- a/test/regress/regress1/arith/arith-int-050.cvc
+++ b/test/regress/regress1/arith/arith-int-050.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-20 * x0) + (-19 * x1) + (6 * x2) + (32 * x3) > 16 ;
ASSERT (-1 * x0) + (-30 * x1) + (15 * x2) + (7 * x3) < -10 ;
diff --git a/test/regress/regress1/arith/arith-int-051.cvc b/test/regress/regress1/arith/arith-int-051.cvc
index 9a2497432..68654a7df 100644
--- a/test/regress/regress1/arith/arith-int-051.cvc
+++ b/test/regress/regress1/arith/arith-int-051.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-13 * x0) + (7 * x1) + (-3 * x2) + (9 * x3) = -3 ;
ASSERT (17 * x0) + (-22 * x1) + (-15 * x2) + (-21 * x3) >= 9 ;
diff --git a/test/regress/regress1/arith/arith-int-052.cvc b/test/regress/regress1/arith/arith-int-052.cvc
index 83fdc89c8..9c9433ede 100644
--- a/test/regress/regress1/arith/arith-int-052.cvc
+++ b/test/regress/regress1/arith/arith-int-052.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-25 * x0) + (-23 * x1) + (11 * x2) + (10 * x3) = 7 ;
ASSERT (32 * x0) + (-15 * x1) + (-1 * x2) + (29 * x3) > -25 ;
diff --git a/test/regress/regress1/arith/arith-int-053.cvc b/test/regress/regress1/arith/arith-int-053.cvc
index fa38fa3da..544d53fb9 100644
--- a/test/regress/regress1/arith/arith-int-053.cvc
+++ b/test/regress/regress1/arith/arith-int-053.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-21 * x0) + (21 * x1) + (23 * x2) + (-20 * x3) = -8 ;
ASSERT (-31 * x0) + (-15 * x1) + (-23 * x2) + (29 * x3) = 17;
diff --git a/test/regress/regress1/arith/arith-int-054.cvc b/test/regress/regress1/arith/arith-int-054.cvc
index 9b0066966..5b4181a11 100644
--- a/test/regress/regress1/arith/arith-int-054.cvc
+++ b/test/regress/regress1/arith/arith-int-054.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-31 * x0) + (-29 * x1) + (6 * x2) + (8 * x3) = -10 ;
ASSERT (0 * x0) + (8 * x1) + (-20 * x2) + (12 * x3) = 16 ;
diff --git a/test/regress/regress1/arith/arith-int-055.cvc b/test/regress/regress1/arith/arith-int-055.cvc
index 9729fb565..fdfa45848 100644
--- a/test/regress/regress1/arith/arith-int-055.cvc
+++ b/test/regress/regress1/arith/arith-int-055.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-21 * x0) + (-4 * x1) + (-28 * x2) + (-7 * x3) = -23 ;
ASSERT (-7 * x0) + (-21 * x1) + (29 * x2) + (11 * x3) = 29 ;
diff --git a/test/regress/regress1/arith/arith-int-056.cvc b/test/regress/regress1/arith/arith-int-056.cvc
index e1c3ee1da..394b3dd4e 100644
--- a/test/regress/regress1/arith/arith-int-056.cvc
+++ b/test/regress/regress1/arith/arith-int-056.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-25 * x0) + (23 * x1) + (29 * x2) + (21 * x3) = -2 ;
ASSERT (1 * x0) + (10 * x1) + (-32 * x2) + (-17 * x3) = -2 ;
diff --git a/test/regress/regress1/arith/arith-int-057.cvc b/test/regress/regress1/arith/arith-int-057.cvc
index 4e7b939b4..252601514 100644
--- a/test/regress/regress1/arith/arith-int-057.cvc
+++ b/test/regress/regress1/arith/arith-int-057.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-8 * x0) + (10 * x1) + (-25 * x2) + (-10 * x3) = -18 ;
ASSERT (27 * x0) + (5 * x1) + (8 * x2) + (13 * x3) = -8;
diff --git a/test/regress/regress1/arith/arith-int-058.cvc b/test/regress/regress1/arith/arith-int-058.cvc
index 4d964f1c6..7e2a04d45 100644
--- a/test/regress/regress1/arith/arith-int-058.cvc
+++ b/test/regress/regress1/arith/arith-int-058.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-15 * x0) + (3 * x1) + (31 * x2) + (2 * x3) = -18 ;
ASSERT (-25 * x0) + (-10 * x1) + (15 * x2) + (29 * x3) = -18 ;
diff --git a/test/regress/regress1/arith/arith-int-059.cvc b/test/regress/regress1/arith/arith-int-059.cvc
index 841d9c8e1..87773679e 100644
--- a/test/regress/regress1/arith/arith-int-059.cvc
+++ b/test/regress/regress1/arith/arith-int-059.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (31 * x0) + (-19 * x1) + (0 * x2) + (32 * x3) = -14 ;
ASSERT (12 * x0) + (-25 * x1) + (-32 * x2) + (-18 * x3) = 18 ;
diff --git a/test/regress/regress1/arith/arith-int-060.cvc b/test/regress/regress1/arith/arith-int-060.cvc
index 227cb49b1..74dd16dca 100644
--- a/test/regress/regress1/arith/arith-int-060.cvc
+++ b/test/regress/regress1/arith/arith-int-060.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (3 * x0) + (8 * x1) + (26 * x2) + (-17 * x3) = 31 ;
ASSERT (-14 * x0) + (25 * x1) + (4 * x2) + (-8 * x3) = 15 ;
diff --git a/test/regress/regress1/arith/arith-int-061.cvc b/test/regress/regress1/arith/arith-int-061.cvc
index 4a3cc28d0..b3bd247b2 100644
--- a/test/regress/regress1/arith/arith-int-061.cvc
+++ b/test/regress/regress1/arith/arith-int-061.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (16 * x0) + (20 * x1) + (-8 * x2) + (-27 * x3) = -2 ;
ASSERT (15 * x0) + (9 * x1) + (-1 * x2) + (4 * x3) = 1 ;
diff --git a/test/regress/regress1/arith/arith-int-062.cvc b/test/regress/regress1/arith/arith-int-062.cvc
index f9a3156a2..0a185eb68 100644
--- a/test/regress/regress1/arith/arith-int-062.cvc
+++ b/test/regress/regress1/arith/arith-int-062.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (11 * x0) + (22 * x1) + (19 * x2) + (-8 * x3) = 12 ;
ASSERT (23 * x0) + (-6 * x1) + (-5 * x2) + (26 * x3) = 0 ;
diff --git a/test/regress/regress1/arith/arith-int-063.cvc b/test/regress/regress1/arith/arith-int-063.cvc
index d88104688..13c4aae2e 100644
--- a/test/regress/regress1/arith/arith-int-063.cvc
+++ b/test/regress/regress1/arith/arith-int-063.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (20 * x0) + (-10 * x1) + (-10 * x2) + (26 * x3) = -9 ;
ASSERT (10 * x0) + (0 * x1) + (16 * x2) + (7 * x3) = 7 ;
diff --git a/test/regress/regress1/arith/arith-int-064.cvc b/test/regress/regress1/arith/arith-int-064.cvc
index 21ca822e1..f50b3cd97 100644
--- a/test/regress/regress1/arith/arith-int-064.cvc
+++ b/test/regress/regress1/arith/arith-int-064.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-8 * x0) + (-11 * x1) + (27 * x2) + (4 * x3) = 6 ;
ASSERT (32 * x0) + (27 * x1) + (31 * x2) + (-13 * x3) = 21 ;
diff --git a/test/regress/regress1/arith/arith-int-065.cvc b/test/regress/regress1/arith/arith-int-065.cvc
index b1b9e1b51..354eb981c 100644
--- a/test/regress/regress1/arith/arith-int-065.cvc
+++ b/test/regress/regress1/arith/arith-int-065.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (3 * x0) + (-21 * x1) + (-3 * x2) + (6 * x3) = -18 ;
ASSERT (-15 * x0) + (19 * x1) + (-21 * x2) + (-29 * x3) = -8 ;
diff --git a/test/regress/regress1/arith/arith-int-066.cvc b/test/regress/regress1/arith/arith-int-066.cvc
index 9532b4198..f53a254bd 100644
--- a/test/regress/regress1/arith/arith-int-066.cvc
+++ b/test/regress/regress1/arith/arith-int-066.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (28 * x0) + (-8 * x1) + (32 * x2) + (-3 * x3) = -18 ;
ASSERT (-4 * x0) + (5 * x1) + (-2 * x2) + (-17 * x3) > 19 ;
diff --git a/test/regress/regress1/arith/arith-int-067.cvc b/test/regress/regress1/arith/arith-int-067.cvc
index 5d7b52e69..61159e9aa 100644
--- a/test/regress/regress1/arith/arith-int-067.cvc
+++ b/test/regress/regress1/arith/arith-int-067.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-25 * x0) + (-32 * x1) + (-29 * x2) + (-9 * x3) = -2 ;
ASSERT (22 * x0) + (10 * x1) + (-18 * x2) + (2 * x3) = -17 ;
diff --git a/test/regress/regress1/arith/arith-int-068.cvc b/test/regress/regress1/arith/arith-int-068.cvc
index 107a21a12..683d36801 100644
--- a/test/regress/regress1/arith/arith-int-068.cvc
+++ b/test/regress/regress1/arith/arith-int-068.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-20 * x0) + (-8 * x1) + (5 * x2) + (-7 * x3) = -7 ;
ASSERT (-30 * x0) + (24 * x1) + (-4 * x2) + (-30 * x3) = 22 ;
diff --git a/test/regress/regress1/arith/arith-int-069.cvc b/test/regress/regress1/arith/arith-int-069.cvc
index 3fab229b0..356a28013 100644
--- a/test/regress/regress1/arith/arith-int-069.cvc
+++ b/test/regress/regress1/arith/arith-int-069.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-12 * x0) + (20 * x1) + (2 * x2) + (-24 * x3) = 16 ;
ASSERT (-32 * x0) + (27 * x1) + (1 * x2) + (-3 * x3) = -3 ;
diff --git a/test/regress/regress1/arith/arith-int-070.cvc b/test/regress/regress1/arith/arith-int-070.cvc
index cd828da5f..791b3b8af 100644
--- a/test/regress/regress1/arith/arith-int-070.cvc
+++ b/test/regress/regress1/arith/arith-int-070.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (0 * x0) + (-16 * x1) + (14 * x2) + (20 * x3) = 1 ;
ASSERT (-27 * x0) + (-5 * x1) + (-22 * x2) + (-24 * x3) = -7 ;
diff --git a/test/regress/regress1/arith/arith-int-071.cvc b/test/regress/regress1/arith/arith-int-071.cvc
index ce5336476..d44b18b45 100644
--- a/test/regress/regress1/arith/arith-int-071.cvc
+++ b/test/regress/regress1/arith/arith-int-071.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (22 * x0) + (3 * x1) + (-17 * x2) + (-21 * x3) = -9 ;
ASSERT (-12 * x0) + (-9 * x1) + (-9 * x2) + (-16 * x3) = -12 ;
diff --git a/test/regress/regress1/arith/arith-int-072.cvc b/test/regress/regress1/arith/arith-int-072.cvc
index 10222deae..fb13a6616 100644
--- a/test/regress/regress1/arith/arith-int-072.cvc
+++ b/test/regress/regress1/arith/arith-int-072.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (1 * x0) + (-1 * x1) + (-16 * x2) + (6 * x3) = -11 ;
ASSERT (-17 * x0) + (17 * x1) + (-15 * x2) + (24 * x3) = -21 ;
diff --git a/test/regress/regress1/arith/arith-int-073.cvc b/test/regress/regress1/arith/arith-int-073.cvc
index 98e74be8f..784190cad 100644
--- a/test/regress/regress1/arith/arith-int-073.cvc
+++ b/test/regress/regress1/arith/arith-int-073.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (8 * x0) + (-14 * x1) + (0 * x2) + (7 * x3) = 26 ;
ASSERT (-7 * x0) + (-14 * x1) + (15 * x2) + (31 * x3) = 8 ;
diff --git a/test/regress/regress1/arith/arith-int-074.cvc b/test/regress/regress1/arith/arith-int-074.cvc
index 28cc48186..914cbe8e3 100644
--- a/test/regress/regress1/arith/arith-int-074.cvc
+++ b/test/regress/regress1/arith/arith-int-074.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (14 * x0) + (-6 * x1) + (-23 * x2) + (-8 * x3) = -18 ;
ASSERT (-11 * x0) + (12 * x1) + (8 * x2) + (-1 * x3) = -32 ;
diff --git a/test/regress/regress1/arith/arith-int-075.cvc b/test/regress/regress1/arith/arith-int-075.cvc
index 3b5131e8b..d3851e284 100644
--- a/test/regress/regress1/arith/arith-int-075.cvc
+++ b/test/regress/regress1/arith/arith-int-075.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-8 * x0) + (29 * x1) + (15 * x2) + (32 * x3) = 32 ;
ASSERT (18 * x0) + (-8 * x1) + (18 * x2) + (22 * x3) = 20 ;
diff --git a/test/regress/regress1/arith/arith-int-076.cvc b/test/regress/regress1/arith/arith-int-076.cvc
index 2c8de7cdf..25a3a7d35 100644
--- a/test/regress/regress1/arith/arith-int-076.cvc
+++ b/test/regress/regress1/arith/arith-int-076.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-20 * x0) + (0 * x1) + (4 * x2) + (29 * x3) = -15 ;
ASSERT (3 * x0) + (19 * x1) + (21 * x2) + (-32 * x3) = 11 ;
diff --git a/test/regress/regress1/arith/arith-int-077.cvc b/test/regress/regress1/arith/arith-int-077.cvc
index d14da386e..7e4482093 100644
--- a/test/regress/regress1/arith/arith-int-077.cvc
+++ b/test/regress/regress1/arith/arith-int-077.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (26 * x0) + (-28 * x1) + (27 * x2) + (8 * x3) = 31 ;
ASSERT (-32 * x0) + (11 * x1) + (-5 * x2) + (14 * x3) = 2;
diff --git a/test/regress/regress1/arith/arith-int-078.cvc b/test/regress/regress1/arith/arith-int-078.cvc
index 3197c6524..eacccc375 100644
--- a/test/regress/regress1/arith/arith-int-078.cvc
+++ b/test/regress/regress1/arith/arith-int-078.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (17 * x0) + (-14 * x1) + (13 * x2) + (13 * x3) = -18 ;
ASSERT (13 * x0) + (16 * x1) + (-12 * x2) + (19 * x3) = -20 ;
diff --git a/test/regress/regress1/arith/arith-int-080.cvc b/test/regress/regress1/arith/arith-int-080.cvc
index 8be0f9a73..bf6b90c67 100644
--- a/test/regress/regress1/arith/arith-int-080.cvc
+++ b/test/regress/regress1/arith/arith-int-080.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (5 * x0) + (-17 * x1) + (15 * x2) + (-15 * x3) = -14 ;
ASSERT (-28 * x0) + (-17 * x1) + (-29 * x2) + (-19 * x3) = 14;
diff --git a/test/regress/regress1/arith/arith-int-081.cvc b/test/regress/regress1/arith/arith-int-081.cvc
index 546148376..47cc66ae2 100644
--- a/test/regress/regress1/arith/arith-int-081.cvc
+++ b/test/regress/regress1/arith/arith-int-081.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-8 * x0) + (31 * x1) + (-23 * x2) + (-8 * x3) = 8;
ASSERT (24 * x0) + (-2 * x1) + (2 * x2) + (-2 * x3) >= -17 ;
diff --git a/test/regress/regress1/arith/arith-int-082.cvc b/test/regress/regress1/arith/arith-int-082.cvc
index 62bd45de7..a6245f036 100644
--- a/test/regress/regress1/arith/arith-int-082.cvc
+++ b/test/regress/regress1/arith/arith-int-082.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-29 * x0) + (-3 * x1) + (27 * x2) + (13 * x3) = -10 ;
ASSERT (7 * x0) + (-17 * x1) + (11 * x2) + (-30 * x3) <= 6 ;
diff --git a/test/regress/regress1/arith/arith-int-083.cvc b/test/regress/regress1/arith/arith-int-083.cvc
index 6b1084353..3a7c635cc 100644
--- a/test/regress/regress1/arith/arith-int-083.cvc
+++ b/test/regress/regress1/arith/arith-int-083.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (19 * x0) + (-31 * x1) + (31 * x2) + (28 * x3) = -13 ;
ASSERT (1 * x0) + (13 * x1) + (12 * x2) + (-15 * x3) > -8 ;
diff --git a/test/regress/regress1/arith/arith-int-084.cvc b/test/regress/regress1/arith/arith-int-084.cvc
index 5f0e17afe..d4a0a966c 100644
--- a/test/regress/regress1/arith/arith-int-084.cvc
+++ b/test/regress/regress1/arith/arith-int-084.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-2 * x0) + (-13 * x1) + (-14 * x2) + (-26 * x3) <= 4 ;
ASSERT (-17 * x0) + (-17 * x1) + (21 * x2) + (-4 * x3) < 18 ;
diff --git a/test/regress/regress1/arith/arith-int-085.cvc b/test/regress/regress1/arith/arith-int-085.cvc
index 74dd714e8..b1a343e73 100644
--- a/test/regress/regress1/arith/arith-int-085.cvc
+++ b/test/regress/regress1/arith/arith-int-085.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
%% down from 3
x0, x1, x2, x3 : INT;
ASSERT (22 * x0) + (-25 * x1) + (-20 * x2) + (8 * x3) = -6 ;
diff --git a/test/regress/regress1/arith/arith-int-086.cvc b/test/regress/regress1/arith/arith-int-086.cvc
index 64c212b3c..6ee96589b 100644
--- a/test/regress/regress1/arith/arith-int-086.cvc
+++ b/test/regress/regress1/arith/arith-int-086.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-16 * x0) + (28 * x1) + (2 * x2) + (7 * x3) = -25 ;
ASSERT (-20 * x0) + (-24 * x1) + (4 * x2) + (32 * x3) = -22 ;
diff --git a/test/regress/regress1/arith/arith-int-087.cvc b/test/regress/regress1/arith/arith-int-087.cvc
index 312c08917..b969df1a3 100644
--- a/test/regress/regress1/arith/arith-int-087.cvc
+++ b/test/regress/regress1/arith/arith-int-087.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-4 * x0) + (25 * x1) + (-2 * x2) + (-16 * x3) = 27 ;
ASSERT (-11 * x0) + (26 * x1) + (18 * x2) + (-18 * x3) = -15 ;
diff --git a/test/regress/regress1/arith/arith-int-088.cvc b/test/regress/regress1/arith/arith-int-088.cvc
index 5212640be..de0d23844 100644
--- a/test/regress/regress1/arith/arith-int-088.cvc
+++ b/test/regress/regress1/arith/arith-int-088.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-19 * x0) + (-9 * x1) + (-27 * x2) + (9 * x3) = -1 ;
ASSERT (-26 * x0) + (11 * x1) + (23 * x2) + (-5 * x3) >= 20 ;
diff --git a/test/regress/regress1/arith/arith-int-089.cvc b/test/regress/regress1/arith/arith-int-089.cvc
index 7ff36d29e..e50daa9de 100644
--- a/test/regress/regress1/arith/arith-int-089.cvc
+++ b/test/regress/regress1/arith/arith-int-089.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (14 * x0) + (-14 * x1) + (-29 * x2) + (31 * x3) = -15 ;
ASSERT (-14 * x0) + (2 * x1) + (26 * x2) + (29 * x3) = 25 ;
diff --git a/test/regress/regress1/arith/arith-int-090.cvc b/test/regress/regress1/arith/arith-int-090.cvc
index 52b9c13f0..74d4ba4db 100644
--- a/test/regress/regress1/arith/arith-int-090.cvc
+++ b/test/regress/regress1/arith/arith-int-090.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-13 * x0) + (-14 * x1) + (-10 * x2) + (32 * x3) = 11 ;
ASSERT (28 * x0) + (21 * x1) + (-20 * x2) + (-32 * x3) > -31 ;
diff --git a/test/regress/regress1/arith/arith-int-091.cvc b/test/regress/regress1/arith/arith-int-091.cvc
index 29a19db39..c03b544a3 100644
--- a/test/regress/regress1/arith/arith-int-091.cvc
+++ b/test/regress/regress1/arith/arith-int-091.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (26 * x0) + (32 * x1) + (-26 * x2) + (-26 * x3) = -26 ;
ASSERT (30 * x0) + (17 * x1) + (28 * x2) + (-9 * x3) = -21 ;
diff --git a/test/regress/regress1/arith/arith-int-092.cvc b/test/regress/regress1/arith/arith-int-092.cvc
index 51c8a6bc4..d080cde0c 100644
--- a/test/regress/regress1/arith/arith-int-092.cvc
+++ b/test/regress/regress1/arith/arith-int-092.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-20 * x0) + (19 * x1) + (16 * x2) + (-27 * x3) = -22 ;
ASSERT (12 * x0) + (-18 * x1) + (-25 * x2) + (-1 * x3) = -22 ;
diff --git a/test/regress/regress1/arith/arith-int-093.cvc b/test/regress/regress1/arith/arith-int-093.cvc
index 7d2123d41..e910def47 100644
--- a/test/regress/regress1/arith/arith-int-093.cvc
+++ b/test/regress/regress1/arith/arith-int-093.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (22 * x0) + (-2 * x1) + (-1 * x2) + (-24 * x3) = 8 ;
ASSERT (-6 * x0) + (9 * x1) + (-20 * x2) + (-23 * x3) = 14 ;
diff --git a/test/regress/regress1/arith/arith-int-094.cvc b/test/regress/regress1/arith/arith-int-094.cvc
index a5f1aefce..2204bba4e 100644
--- a/test/regress/regress1/arith/arith-int-094.cvc
+++ b/test/regress/regress1/arith/arith-int-094.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (-7 * x0) + (-11 * x1) + (26 * x2) + (10 * x3) = 31 ;
ASSERT (-17 * x0) + (-20 * x1) + (24 * x2) + (-9 * x3) = -32 ;
diff --git a/test/regress/regress1/arith/arith-int-095.cvc b/test/regress/regress1/arith/arith-int-095.cvc
index bc47d6f49..e803dbe9b 100644
--- a/test/regress/regress1/arith/arith-int-095.cvc
+++ b/test/regress/regress1/arith/arith-int-095.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x0, x1, x2, x3 : INT;
ASSERT (2 * x0) + (28 * x1) + (3 * x2) + (8 * x3) > -32 ;
ASSERT (-15 * x0) + (21 * x1) + (-11 * x2) + (28 * x3) <= -19 ;
diff --git a/test/regress/regress1/arith/arith-int-096.cvc b/test/regress/regress1/arith/arith-int-096.cvc
index 2f6cf3155..354ae180d 100644
--- a/test/regress/regress1/arith/arith-int-096.cvc
+++ b/test/regress/regress1/arith/arith-int-096.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (23 * x0) + (24 * x1) + (19 * x2) + (-3 * x3) = -16 ;
ASSERT (2 * x0) + (-13 * x1) + (5 * x2) + (-1 * x3) = 28;
diff --git a/test/regress/regress1/arith/arith-int-097.cvc b/test/regress/regress1/arith/arith-int-097.cvc
index b05061192..67eb614eb 100644
--- a/test/regress/regress1/arith/arith-int-097.cvc
+++ b/test/regress/regress1/arith/arith-int-097.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (19 * x0) + (-11 * x1) + (-19 * x2) + (5 * x3) = 26 ;
ASSERT (1 * x0) + (-28 * x1) + (-2 * x2) + (15 * x3) < 9 ;
diff --git a/test/regress/regress1/arith/arith-int-099.cvc b/test/regress/regress1/arith/arith-int-099.cvc
index 0d74dcb39..57a45de03 100644
--- a/test/regress/regress1/arith/arith-int-099.cvc
+++ b/test/regress/regress1/arith/arith-int-099.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-31 * x0) + (-20 * x1) + (-30 * x2) + (-28 * x3) = -24 ;
ASSERT (11 * x0) + (-32 * x1) + (-2 * x2) + (8 * x3) <= 16 ;
diff --git a/test/regress/regress1/arith/arith-int-100.cvc b/test/regress/regress1/arith/arith-int-100.cvc
index 7e07bee14..66be1f8f7 100644
--- a/test/regress/regress1/arith/arith-int-100.cvc
+++ b/test/regress/regress1/arith/arith-int-100.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (27 * x0) + (-21 * x1) + (-6 * x2) + (-6 * x3) > -15 ;
ASSERT (-5 * x0) + (-10 * x1) + (2 * x2) + (-16 * x3) <= -7 ;
diff --git a/test/regress/regress1/arith/bug547.1.smt2 b/test/regress/regress1/arith/bug547.1.smt2
index 4b7cf9780..38d1dfcb1 100644
--- a/test/regress/regress1/arith/bug547.1.smt2
+++ b/test/regress/regress1/arith/bug547.1.smt2
@@ -1,5 +1,5 @@
-; COMMAND-LINE: --rewrite-divk
-; EXPECT: unknown
+; COMMAND-LINE: --rewrite-divk --nl-ext-tplanes
+; EXPECT: sat
(set-logic QF_NIA)
(declare-fun x () Int)
(declare-fun y () Int)
diff --git a/test/regress/regress1/boolean.cvc b/test/regress/regress1/boolean.cvc
index eb0e7ab52..2c861c0f0 100644
--- a/test/regress/regress1/boolean.cvc
+++ b/test/regress/regress1/boolean.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
p : BOOLEAN;
q : BOOLEAN;
r : BOOLEAN;
diff --git a/test/regress/regress1/fmf/fmf-strange-bounds.smt2 b/test/regress/regress1/fmf/fmf-strange-bounds.smt2
index 7812c2431..20738245c 100644
--- a/test/regress/regress1/fmf/fmf-strange-bounds.smt2
+++ b/test/regress/regress1/fmf/fmf-strange-bounds.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --fmf-bound
+; COMMAND-LINE: --fmf-bound --finite-model-find
; EXPECT: sat
(set-logic ALL)
(set-info :status sat)
@@ -17,11 +17,16 @@
(assert (>= (h (g 77)) 2))
(assert (not (= (g 77) (f 77))))
-(assert (forall ((x Int) (y Int) (z U)) (=>
+(assert (forall ((x Int) (z U)) (=>
(or (= z (f x)) (= z (g x)))
(=> (member x S)
-(=> (and (<= 0 y) (<= y (h z)))
-(P x y z))))))
+(P x 0 z)))))
+
+(assert (forall ((x Int) (y Int) (z U)) (=>
+(or (= x 5) (= x 6))
+(=> (and (<= 0 y) (<= y x))
+(P x y z)))))
+
(declare-fun Q (U Int) Bool)
diff --git a/test/regress/regress1/fmf/ko-bound-set.cvc b/test/regress/regress1/fmf/ko-bound-set.cvc
index eebcbc2f8..5306a1513 100644
--- a/test/regress/regress1/fmf/ko-bound-set.cvc
+++ b/test/regress/regress1/fmf/ko-bound-set.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
OPTION "finite-model-find";
OPTION "fmf-bound-int";
OPTION "produce-models";
diff --git a/test/regress/regress1/hole6.cvc b/test/regress/regress1/hole6.cvc
index dfa9b72d5..5ec31d801 100644
--- a/test/regress/regress1/hole6.cvc
+++ b/test/regress/regress1/hole6.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x_1 : BOOLEAN;
x_2 : BOOLEAN;
x_3 : BOOLEAN;
diff --git a/test/regress/regress1/quantifiers/set-choice-koikonomou.cvc b/test/regress/regress1/quantifiers/set-choice-koikonomou.cvc
index f7407a2a5..6f2a8764b 100644
--- a/test/regress/regress1/quantifiers/set-choice-koikonomou.cvc
+++ b/test/regress/regress1/quantifiers/set-choice-koikonomou.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
OPTION "finite-model-find";
OPTION "fmf-bound-int";
diff --git a/test/regress/regress1/rr-verify/regex.sy b/test/regress/regress1/rr-verify/regex.sy
index 6c6da3dd2..2d911e56a 100644
--- a/test/regress/regress1/rr-verify/regex.sy
+++ b/test/regress/regress1/rr-verify/regex.sy
@@ -1,17 +1,18 @@
-; COMMAND-LINE: --sygus-rr --sygus-samples=1000 --sygus-abort-size=3 --sygus-rr-verify-abort --no-sygus-sym-break
+; COMMAND-LINE: --lang=sygus2 --sygus-rr --sygus-samples=1000 --sygus-abort-size=3 --sygus-rr-verify-abort --no-sygus-sym-break
; EXPECT: (error "Maximum term size (3) for enumerative SyGuS exceeded.")
; SCRUBBER: grep -v -E '(\(define-fun|\(candidate-rewrite)'
; EXIT: 1
(set-logic SLIA)
-(synth-fun f ((x String) (y String)) Bool (
+(synth-fun f ((x String) (y String)) Bool
+((Start Bool) (StartRe RegLan) (StartStr String)) (
(Start Bool (
true
false
(= StartStr StartStr)
- (str.in.re StartStr StartRe)
+ (str.in_re StartStr StartRe)
))
(StartRe RegLan (
@@ -19,7 +20,7 @@
(re.++ StartRe StartRe)
(re.union StartRe StartRe)
(re.* StartRe)
- (str.to.re StartStr)
+ (str.to_re StartStr)
))
(StartStr String (
diff --git a/test/regress/regress1/strings/bug686dd.smt2 b/test/regress/regress1/strings/bug686dd.smt2
index 0cb9fac26..b5c9457ff 100644
--- a/test/regress/regress1/strings/bug686dd.smt2
+++ b/test/regress/regress1/strings/bug686dd.smt2
@@ -8,7 +8,7 @@
(declare-fun root6 () T)
(assert (and
-(str.in.re root5 (re.loop (re.range "0" "9") 4 4) )
-(str.in.re (TCb root6) (re.loop (re.range "0" "9") 4 4) )
+(str.in.re root5 ((_ re.loop 4 4) (re.range "0" "9")) )
+(str.in.re (TCb root6) ((_ re.loop 4 4) (re.range "0" "9")) )
) )
(check-sat)
diff --git a/test/regress/regress1/strings/pierre150331.smt2 b/test/regress/regress1/strings/pierre150331.smt2
index add60d534..e04db8e9a 100644
--- a/test/regress/regress1/strings/pierre150331.smt2
+++ b/test/regress/regress1/strings/pierre150331.smt2
@@ -6,7 +6,7 @@
(define-fun stringEval ((?s String)) Bool (str.in.re ?s
(re.union
(str.to.re "H")
-(re.++ (re.loop (str.to.re "{") 2 2 ) (re.loop (re.union re.nostr (re.range "" "]") (re.range "" "^") ) 2 4 ) ) ) ) )
+(re.++ ((_ re.loop 2 2) (str.to.re "{") ) ((_ re.loop 2 4) (re.union re.nostr (re.range "" "]") (re.range "" "^") ) ) ) ) ) )
(declare-fun s0() String)
(declare-fun s1() String)
(declare-fun s2() String)
diff --git a/test/regress/regress1/strings/reloop.smt2 b/test/regress/regress1/strings/reloop.smt2
index 22537b957..6230d1656 100644
--- a/test/regress/regress1/strings/reloop.smt2
+++ b/test/regress/regress1/strings/reloop.smt2
@@ -8,11 +8,11 @@
(declare-fun z () String)
(declare-fun w () String)
-(assert (str.in.re x (re.loop (str.to.re "a") 5)))
-(assert (str.in.re y (re.loop (str.to.re "b") 2 5)))
-(assert (str.in.re z (re.loop (str.to.re "c") 5)))
+(assert (str.in.re x ((_ re.^ 5) (str.to.re "a"))))
+(assert (str.in.re y ((_ re.loop 2 5) (str.to.re "b"))))
+(assert (str.in.re z ((_ re.loop 5 15) (str.to.re "c"))))
(assert (> (str.len z) 7))
-(assert (str.in.re w (re.loop (str.to.re "b") 2 7)))
+(assert (str.in.re w ((_ re.loop 2 7) (str.to.re "b"))))
(assert (> (str.len w) 2))
(assert (< (str.len w) 5))
diff --git a/test/regress/regress1/sygus/dt-test-ns.sy b/test/regress/regress1/sygus/dt-test-ns.sy
index 3d078cc25..90fa57827 100644
--- a/test/regress/regress1/sygus/dt-test-ns.sy
+++ b/test/regress/regress1/sygus/dt-test-ns.sy
@@ -1,6 +1,6 @@
; EXPECT: unsat
; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --sygus-out=status
-(set-logic LIA)
+(set-logic DTLIA)
(declare-datatypes ((List 0)) (((cons (head Int) (tail List)) (nil))))
@@ -8,6 +8,6 @@
(declare-var x Int)
-(constraint (is-cons (f x)))
+(constraint ((_ is cons) (f x)))
(constraint (and (= (head (f x)) x) (= (head (f x)) (+ 5 (head (tail (f x)))))))
(check-synth)
diff --git a/test/regress/regress1/sygus/hd-19-d1-prog-dup-op.sy b/test/regress/regress1/sygus/hd-19-d1-prog-dup-op.sy
index abcfc2217..089a8f11f 100644
--- a/test/regress/regress1/sygus/hd-19-d1-prog-dup-op.sy
+++ b/test/regress/regress1/sygus/hd-19-d1-prog-dup-op.sy
@@ -1,14 +1,15 @@
; EXPECT: unsat
-; COMMAND-LINE: --cegqi-si=all --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --sygus-out=status
(set-logic BV)
-(define-fun hd19 ((x (BitVec 32)) (m (BitVec 32)) (k (BitVec 32))) (BitVec 32)
- (bvxor x (bvxor (bvshl (bvand (bvxor (bvlshr x k) x) m) k) (bvand (bvxor (bvlshr x k) x) m))))
+(define-fun hd19 ((x (_ BitVec 32)) (m (_ BitVec 32)) (k (_ BitVec 32))) (_ BitVec 32)
+ (bvxor x (bvxor (bvshl (bvand (bvxor (bvlshr x k) x) m) k) (bvand (bvxor (bvlshr x k) x) m))))
; bvand is a duplicate
-(synth-fun f ((x (BitVec 32)) (m (BitVec 32)) (k (BitVec 32))) (BitVec 32)
- ((Start (BitVec 32) ((bvand Start Start)
+(synth-fun f ((x (_ BitVec 32)) (m (_ BitVec 32)) (k (_ BitVec 32))) (_ BitVec 32)
+ ((Start (_ BitVec 32)))
+ ((Start (_ BitVec 32) ((bvand Start Start)
(bvsub Start Start)
(bvxor Start Start)
(bvor Start Start)
@@ -23,10 +24,9 @@
k))))
-(declare-var x (BitVec 32))
-(declare-var m (BitVec 32))
-(declare-var k (BitVec 32))
+(declare-var x (_ BitVec 32))
+(declare-var m (_ BitVec 32))
+(declare-var k (_ BitVec 32))
(constraint (= (hd19 x m k) (f x m k)))
(check-synth)
-
diff --git a/test/regress/regress1/sygus/issue3461.sy b/test/regress/regress1/sygus/issue3461.sy
index 1f839c229..08b5738c1 100644
--- a/test/regress/regress1/sygus/issue3461.sy
+++ b/test/regress/regress1/sygus/issue3461.sy
@@ -1,15 +1,16 @@
; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --sygus-out=status
(set-logic ALL_SUPPORTED)
(declare-datatype Doc ((D (owner Int) (body Int))))
-(declare-datatype Policy
- ((p (principal Int))
+(declare-datatype Policy
+ ((p (principal Int))
(por (left Policy) (right Policy))))
(synth-fun mkPolicy ((d Doc)) Policy
+ ((Start Policy) (Q Policy))
((Start Policy (Q))
(Q Policy ((p 0) (p 1) (por Q Q))))
)
diff --git a/test/regress/regress1/sygus/list-head-x.sy b/test/regress/regress1/sygus/list-head-x.sy
index 83ac8290d..ae2bcc00e 100644
--- a/test/regress/regress1/sygus/list-head-x.sy
+++ b/test/regress/regress1/sygus/list-head-x.sy
@@ -8,6 +8,6 @@
(declare-var x Int)
-(constraint (is-cons (f x)))
+(constraint ((_ is cons) (f x)))
(constraint (= (head (f x)) (+ x 7)))
(check-synth)
diff --git a/test/regress/regress1/sygus/max.sy b/test/regress/regress1/sygus/max.sy
index 37ed848ef..f191d784f 100644
--- a/test/regress/regress1/sygus/max.sy
+++ b/test/regress/regress1/sygus/max.sy
@@ -1,8 +1,9 @@
; EXPECT: unsat
-; COMMAND-LINE: --cegqi-si=all --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --sygus-out=status
(set-logic LIA)
(synth-fun max ((x Int) (y Int)) Int
+ ((Start Int) (StartBool Bool))
((Start Int (0 1 x y
(+ Start Start)
(- Start Start)
@@ -12,6 +13,7 @@
(<= Start Start)))))
;(synth-fun min ((x Int) (y Int)) Int
+; ((Start Int) (StartBool Bool))
; ((Start Int ((Constant Int) (Variable Int)
; (+ Start Start)
; (- Start Start)
diff --git a/test/regress/regress1/sygus/parity-si-rcons.sy b/test/regress/regress1/sygus/parity-si-rcons.sy
index a836c9726..850cc6610 100644
--- a/test/regress/regress1/sygus/parity-si-rcons.sy
+++ b/test/regress/regress1/sygus/parity-si-rcons.sy
@@ -1,5 +1,5 @@
; EXPECT: unsat
-; COMMAND-LINE: --cegqi-si=all --cegqi-si-abort --decision=internal --cbqi-prereg-inst --cegqi-si-rcons=try --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --cegqi-si=all --cegqi-si-abort --decision=internal --cbqi-prereg-inst --cegqi-si-rcons=try --sygus-out=status
(set-logic BV)
@@ -7,6 +7,7 @@
(xor (not (xor a b)) (not (xor c d))))
(synth-fun NAND ((a Bool) (b Bool) (c Bool) (d Bool)) Bool
+ ((Start Bool) (StartAnd Bool) (Vars Bool) (Constants Bool))
((Start Bool ((not StartAnd) Vars Constants))
(StartAnd Bool ((and Start Start)))
(Vars Bool (a b c d))
diff --git a/test/regress/regress1/sygus/re-concat.sy b/test/regress/regress1/sygus/re-concat.sy
index 3449ed505..ac1172e33 100644
--- a/test/regress/regress1/sygus/re-concat.sy
+++ b/test/regress/regress1/sygus/re-concat.sy
@@ -1,13 +1,13 @@
; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --sygus-out=status
(set-logic SLIA)
-(synth-fun f () RegLan (
+(synth-fun f () RegLan ((Start RegLan) (Tokens String)) (
(Start RegLan (
- (str.to.re Tokens)
+ (str.to_re Tokens)
(re.++ Start Start)))
(Tokens String ("A" "B"))
))
-(constraint (str.in.re "AB" f))
+(constraint (str.in_re "AB" f))
(check-synth)
diff --git a/test/regress/regress1/sygus/simple-regexp.sy b/test/regress/regress1/sygus/simple-regexp.sy
index b4c248de9..b7646725d 100644
--- a/test/regress/regress1/sygus/simple-regexp.sy
+++ b/test/regress/regress1/sygus/simple-regexp.sy
@@ -1,30 +1,32 @@
; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status
+; COMMAND-LINE: --lang=sygus2 --sygus-out=status
(set-logic SLIA)
-(synth-fun P ((x String)) Bool (
-(Start Bool (
- (str.in.re StartStr StartRL)
+(synth-fun P ((x String)) Bool
+ ((Start Bool) (StartStr String) (StartStrC String) (StartRL RegLan) (StartRLi RegLan)) (
+ (Start Bool (
+ (str.in_re StartStr StartRL)
))
-(StartStr String (
- x
- (str.++ StartStr StartStr)
+ (StartStr String (
+ x
+ (str.++ StartStr StartStr)
+ ))
+ (StartStrC String (
+ "A" "B" ""
+ (str.++ StartStrC StartStrC)
+ ))
+ (StartRL RegLan (
+ (re.++ StartRLi StartRLi)
+ (re.inter StartRL StartRL)
+ (re.union StartRL StartRL)
+ (re.* StartRLi)
+ ))
+ (StartRLi RegLan (
+ (str.to_re StartStrC)
+ (re.inter StartRLi StartRLi)
+ (re.union StartRLi StartRLi)
+ (re.++ StartRLi StartRLi)
+ (re.* StartRLi)
))
-(StartStrC String (
- "A" "B" ""
- (str.++ StartStrC StartStrC)))
-(StartRL RegLan (
-(re.++ StartRLi StartRLi)
-(re.inter StartRL StartRL)
-(re.union StartRL StartRL)
-(re.* StartRLi)
-))
-(StartRLi RegLan (
-(str.to.re StartStrC)
-(re.inter StartRLi StartRLi)
-(re.union StartRLi StartRLi)
-(re.++ StartRLi StartRLi)
-(re.* StartRLi)
-))
))
(constraint (P "AAAAA"))
@@ -33,5 +35,5 @@
(constraint (not (P "AB")))
(constraint (not (P "B")))
-; (str.in.re x (re.* (str.to.re "A"))) is a solution
+; (str.in_re x (re.* (str.to_re "A"))) is a solution
(check-synth)
diff --git a/test/regress/regress1/sygus/sygus-uf-ex.sy b/test/regress/regress1/sygus/sygus-uf-ex.sy
index 66880eafa..7e1cd80b3 100644
--- a/test/regress/regress1/sygus/sygus-uf-ex.sy
+++ b/test/regress/regress1/sygus/sygus-uf-ex.sy
@@ -1,18 +1,24 @@
; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status --uf-ho
-(set-logic UFLIA)
-(declare-fun uf ( Int ) Int)
+; COMMAND-LINE: --lang=sygus2 --sygus-out=status --uf-ho
+(set-logic ALL)
+
+(declare-var uf (-> Int Int))
+
(synth-fun f ((x Int) (y Int)) Bool
-((Start Bool (true false
- (<= IntExpr IntExpr )
- (= IntExpr IntExpr )
- (and Start Start )
- (or Start Start )
- (not Start )))
-(IntExpr Int (0 1 x y
- (+ IntExpr IntExpr )
- (- IntExpr IntExpr )))))
+ ((Start Bool) (IntExpr Int))
+ ((Start Bool (true false
+ (<= IntExpr IntExpr)
+ (= IntExpr IntExpr)
+ (and Start Start)
+ (or Start Start)
+ (not Start )))
+ (IntExpr Int (0 1 x y
+ (+ IntExpr IntExpr)
+ (- IntExpr IntExpr)))))
+
(declare-var x Int)
+
(constraint (f (uf x) (uf x)))
(constraint (not (f 3 4)))
+
(check-synth)
diff --git a/test/regress/regress1/test12.cvc b/test/regress/regress1/test12.cvc
index 37687bee1..39ced0428 100644
--- a/test/regress/regress1/test12.cvc
+++ b/test/regress/regress1/test12.cvc
@@ -1,34 +1,34 @@
% COMMAND-LINE: --incremental
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: valid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: valid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: invalid
-% EXPECT: valid
-% EXPECT: valid
-% EXPECT: valid
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: not_entailed
+% EXPECT: entailed
+% EXPECT: entailed
+% EXPECT: entailed
A: TYPE;
P_1: BOOLEAN;
P_2: BOOLEAN;
diff --git a/test/regress/regress2/arith/arith-int-098.cvc b/test/regress/regress2/arith/arith-int-098.cvc
index 08cfd9c9c..cf20f2b61 100644
--- a/test/regress/regress2/arith/arith-int-098.cvc
+++ b/test/regress/regress2/arith/arith-int-098.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
x0, x1, x2, x3 : INT;
ASSERT (-28 * x0) + (12 * x1) + (-19 * x2) + (10 * x3) = 16 ;
ASSERT (19 * x0) + (-25 * x1) + (-8 * x2) + (-32 * x3) = 12;
diff --git a/test/regress/regress2/hole7.cvc b/test/regress/regress2/hole7.cvc
index 1f762477a..e73588bad 100644
--- a/test/regress/regress2/hole7.cvc
+++ b/test/regress/regress2/hole7.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x_1 : BOOLEAN;
x_2 : BOOLEAN;
x_3 : BOOLEAN;
diff --git a/test/regress/regress2/hole8.cvc b/test/regress/regress2/hole8.cvc
index 705c95ea6..a46c4da97 100644
--- a/test/regress/regress2/hole8.cvc
+++ b/test/regress/regress2/hole8.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x_1 : BOOLEAN;
x_2 : BOOLEAN;
x_3 : BOOLEAN;
diff --git a/test/regress/regress2/strings/range-perf.smt2 b/test/regress/regress2/strings/range-perf.smt2
index 62ec10711..33960e124 100644
--- a/test/regress/regress2/strings/range-perf.smt2
+++ b/test/regress/regress2/strings/range-perf.smt2
@@ -2,6 +2,6 @@
; EXPECT: sat
(set-logic QF_SLIA)
(declare-const x String)
-(assert (str.in.re x (re.loop (re.range "0" "9") 12 12)))
+(assert (str.in.re x ((_ re.loop 12 12) (re.range "0" "9"))))
(assert (str.in.re x (re.++ (re.* re.allchar) (str.to.re "01") (re.* re.allchar))))
(check-sat)
diff --git a/test/regress/regress2/sygus/issue4022-conjecture-gen.smt2 b/test/regress/regress2/sygus/issue4022-conjecture-gen.smt2
index 9c3fe7ac5..471cc519b 100644
--- a/test/regress/regress2/sygus/issue4022-conjecture-gen.smt2
+++ b/test/regress/regress2/sygus/issue4022-conjecture-gen.smt2
@@ -2,7 +2,6 @@
(set-option :conjecture-filter-model true)
(set-option :conjecture-gen true)
(set-option :conjecture-no-filter true)
-(set-option :dt-ref-sk-intro true)
(set-option :quant-ind true)
(set-option :sygus-inference true)
(set-info :status sat)
diff --git a/test/regress/regress2/typed_v1l50016-simp.cvc b/test/regress/regress2/typed_v1l50016-simp.cvc
index b4a1e4b32..1d576ab74 100644
--- a/test/regress/regress2/typed_v1l50016-simp.cvc
+++ b/test/regress/regress2/typed_v1l50016-simp.cvc
@@ -1,4 +1,4 @@
-% EXPECT: invalid
+% EXPECT: not_entailed
DATATYPE
nat = succ(pred : nat) | zero,
diff --git a/test/regress/regress3/hole9.cvc b/test/regress/regress3/hole9.cvc
index e60839f7b..b86b3b039 100644
--- a/test/regress/regress3/hole9.cvc
+++ b/test/regress/regress3/hole9.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x_1 : BOOLEAN;
x_2 : BOOLEAN;
x_3 : BOOLEAN;
diff --git a/test/regress/regress4/hole10.cvc b/test/regress/regress4/hole10.cvc
index ebc8279d3..fb4c41b35 100644
--- a/test/regress/regress4/hole10.cvc
+++ b/test/regress/regress4/hole10.cvc
@@ -1,4 +1,4 @@
-% EXPECT: valid
+% EXPECT: entailed
x_1 : BOOLEAN;
x_2 : BOOLEAN;
x_3 : BOOLEAN;
diff --git a/test/system/boilerplate.cpp b/test/system/boilerplate.cpp
index 141db4eea..2ce50949b 100644
--- a/test/system/boilerplate.cpp
+++ b/test/system/boilerplate.cpp
@@ -29,8 +29,8 @@ int main() {
ExprManager em;
Options opts;
SmtEngine smt(&em);
- Result r = smt.query(em.mkConst(true));
+ Result r = smt.checkEntailed(em.mkConst(true));
- return (Result::VALID == r) ? 0 : 1;
+ return (Result::ENTAILED == r) ? 0 : 1;
}
diff --git a/test/system/statistics.cpp b/test/system/statistics.cpp
index fb9714d4b..2924359e8 100644
--- a/test/system/statistics.cpp
+++ b/test/system/statistics.cpp
@@ -35,9 +35,10 @@ int main() {
Expr y = em.mkVar("y", em.integerType());
smt.assertFormula(em.mkExpr(kind::GT, em.mkExpr(kind::PLUS, x, y), em.mkConst(Rational(5))));
Expr q = em.mkExpr(kind::GT, x, em.mkConst(Rational(0)));
- Result r = smt.query(q);
+ Result r = smt.checkEntailed(q);
- if(r != Result::INVALID) {
+ if (r != Result::NOT_ENTAILED)
+ {
exit(1);
}
@@ -47,7 +48,7 @@ int main() {
}
smt.assertFormula(em.mkExpr(kind::LT, y, em.mkConst(Rational(5))));
- r = smt.query(q);
+ r = smt.checkEntailed(q);
Statistics stats2 = smt.getStatistics();
bool different = false;
for(Statistics::iterator i = stats2.begin(); i != stats2.end(); ++i) {
@@ -68,5 +69,5 @@ int main() {
}
#endif /* CVC4_STATISTICS_ON */
- return r == Result::VALID ? 0 : 1;
+ return r == Result::ENTAILED ? 0 : 1;
}
diff --git a/test/system/two_smt_engines.cpp b/test/system/two_smt_engines.cpp
index a7266e0b0..8698fde0e 100644
--- a/test/system/two_smt_engines.cpp
+++ b/test/system/two_smt_engines.cpp
@@ -28,9 +28,9 @@ int main() {
Options opts;
SmtEngine smt(&em);
SmtEngine smt2(&em);
- Result r = smt.query(em.mkConst(true));
- Result r2 = smt2.query(em.mkConst(true));
+ Result r = smt.checkEntailed(em.mkConst(true));
+ Result r2 = smt2.checkEntailed(em.mkConst(true));
- return r == Result::VALID && r2 == Result::VALID ? 0 : 1;
+ return r == Result::ENTAILED && r2 == Result::ENTAILED ? 0 : 1;
}
diff --git a/test/unit/api/result_black.h b/test/unit/api/result_black.h
index ab5d65e72..cbfc9cf23 100644
--- a/test/unit/api/result_black.h
+++ b/test/unit/api/result_black.h
@@ -29,9 +29,8 @@ class ResultBlack : public CxxTest::TestSuite
void testIsSat();
void testIsUnsat();
void testIsSatUnknown();
- void testIsValid();
- void testIsInvalid();
- void testIsValidUnknown();
+ void testIsEntailed();
+ void testIsEntailmentUnknown();
private:
std::unique_ptr<Solver> d_solver;
@@ -44,9 +43,9 @@ void ResultBlack::testIsNull()
TS_ASSERT(!res_null.isSat());
TS_ASSERT(!res_null.isUnsat());
TS_ASSERT(!res_null.isSatUnknown());
- TS_ASSERT(!res_null.isValid());
- TS_ASSERT(!res_null.isInvalid());
- TS_ASSERT(!res_null.isValidUnknown());
+ TS_ASSERT(!res_null.isEntailed());
+ TS_ASSERT(!res_null.isNotEntailed());
+ TS_ASSERT(!res_null.isEntailmentUnknown());
Sort u_sort = d_solver->mkUninterpretedSort("u");
Term x = d_solver->mkVar(u_sort, "x");
d_solver->assertFormula(x.eqTerm(x));
@@ -100,27 +99,24 @@ void ResultBlack::testIsSatUnknown()
TS_ASSERT(res.isSatUnknown());
}
-void ResultBlack::testIsValid()
+void ResultBlack::testIsEntailed()
{
+ d_solver->setOption("incremental", "true");
Sort u_sort = d_solver->mkUninterpretedSort("u");
- Term x = d_solver->mkVar(u_sort, "x");
- d_solver->assertFormula(x.eqTerm(x).notTerm());
- Result res = d_solver->checkValid();
- TS_ASSERT(res.isValid());
- TS_ASSERT(!res.isValidUnknown());
-}
-
-void ResultBlack::testIsInvalid()
-{
- Sort u_sort = d_solver->mkUninterpretedSort("u");
- Term x = d_solver->mkVar(u_sort, "x");
- d_solver->assertFormula(x.eqTerm(x));
- Result res = d_solver->checkValid();
- TS_ASSERT(res.isInvalid());
- TS_ASSERT(!res.isValidUnknown());
+ Term x = d_solver->mkConst(u_sort, "x");
+ Term y = d_solver->mkConst(u_sort, "y");
+ Term a = x.eqTerm(y).notTerm();
+ Term b = x.eqTerm(y);
+ d_solver->assertFormula(a);
+ Result entailed = d_solver->checkEntailed(a);
+ TS_ASSERT(entailed.isEntailed());
+ TS_ASSERT(!entailed.isEntailmentUnknown());
+ Result not_entailed = d_solver->checkEntailed(b);
+ TS_ASSERT(not_entailed.isNotEntailed());
+ TS_ASSERT(!not_entailed.isEntailmentUnknown());
}
-void ResultBlack::testIsValidUnknown()
+void ResultBlack::testIsEntailmentUnknown()
{
d_solver->setLogic("QF_NIA");
d_solver->setOption("incremental", "false");
@@ -128,9 +124,9 @@ void ResultBlack::testIsValidUnknown()
Sort int_sort = d_solver->getIntegerSort();
Term x = d_solver->mkVar(int_sort, "x");
d_solver->assertFormula(x.eqTerm(x).notTerm());
- Result res = d_solver->checkValid();
- TS_ASSERT(!res.isValid());
- TS_ASSERT(res.isValidUnknown());
+ Result res = d_solver->checkEntailed(x.eqTerm(x));
+ TS_ASSERT(!res.isEntailed());
+ TS_ASSERT(res.isEntailmentUnknown());
TS_ASSERT_EQUALS(res.getUnknownExplanation(), "UNKNOWN_REASON");
}
diff --git a/test/unit/api/solver_black.h b/test/unit/api/solver_black.h
index 27f5aca12..7c9af1714 100644
--- a/test/unit/api/solver_black.h
+++ b/test/unit/api/solver_black.h
@@ -69,6 +69,7 @@ class SolverBlack : public CxxTest::TestSuite
void testMkRoundingMode();
void testMkSepNil();
void testMkString();
+ void testMkChar();
void testMkTerm();
void testMkTermFromOp();
void testMkTrue();
@@ -95,10 +96,9 @@ class SolverBlack : public CxxTest::TestSuite
void testPop3();
void testSimplify();
- void testCheckValid1();
- void testCheckValid2();
- void testCheckValidAssuming1();
- void testCheckValidAssuming2();
+ void testCheckEntailed();
+ void testCheckEntailed1();
+ void testCheckEntailed2();
void testSetInfo();
void testSetLogic();
@@ -556,9 +556,20 @@ void SolverBlack::testMkString()
TS_ASSERT_THROWS_NOTHING(d_solver->mkString(""));
TS_ASSERT_THROWS_NOTHING(d_solver->mkString("asdfasdf"));
TS_ASSERT_EQUALS(d_solver->mkString("asdf\\nasdf").toString(),
- "\"asdf\\\\nasdf\"");
- TS_ASSERT_EQUALS(d_solver->mkString("asdf\\nasdf", true).toString(),
- "\"asdf\\nasdf\"");
+ "\"asdf\\u{5c}nasdf\"");
+ TS_ASSERT_EQUALS(d_solver->mkString("asdf\\u{005c}nasdf", true).toString(),
+ "\"asdf\\u{5c}nasdf\"");
+}
+
+void SolverBlack::testMkChar()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver->mkChar(std::string("0123")));
+ TS_ASSERT_THROWS_NOTHING(d_solver->mkChar("aA"));
+ TS_ASSERT_THROWS(d_solver->mkChar(nullptr), CVC4ApiException&);
+ TS_ASSERT_THROWS(d_solver->mkChar(""), CVC4ApiException&);
+ TS_ASSERT_THROWS(d_solver->mkChar("0g0"), CVC4ApiException&);
+ TS_ASSERT_THROWS(d_solver->mkChar("100000"), CVC4ApiException&);
+ TS_ASSERT_EQUALS(d_solver->mkChar("abc"), d_solver->mkChar("ABC"));
}
void SolverBlack::testMkTerm()
@@ -1104,51 +1115,28 @@ void SolverBlack::testSimplify()
TS_ASSERT_THROWS_NOTHING(d_solver->simplify(f2));
}
-void SolverBlack::testCheckValid1()
+void SolverBlack::testCheckEntailed()
{
d_solver->setOption("incremental", "false");
- TS_ASSERT_THROWS_NOTHING(d_solver->checkValid());
- TS_ASSERT_THROWS(d_solver->checkValid(), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(d_solver->checkEntailed(d_solver->mkTrue()));
+ TS_ASSERT_THROWS(d_solver->checkEntailed(d_solver->mkTrue()),
+ CVC4ApiException&);
}
-void SolverBlack::testCheckValid2()
+void SolverBlack::testCheckEntailed1()
{
+ Sort boolSort = d_solver->getBooleanSort();
+ Term x = d_solver->mkConst(boolSort, "x");
+ Term y = d_solver->mkConst(boolSort, "y");
+ Term z = d_solver->mkTerm(AND, x, y);
d_solver->setOption("incremental", "true");
-
- Sort realSort = d_solver->getRealSort();
- Sort intSort = d_solver->getIntegerSort();
-
- // Constants
- Term x = d_solver->mkConst(intSort, "x");
- Term y = d_solver->mkConst(realSort, "y");
- // Values
- Term three = d_solver->mkReal(3);
- Term neg2 = d_solver->mkReal(-2);
- Term two_thirds = d_solver->mkReal(2, 3);
- // Terms
- Term three_y = d_solver->mkTerm(MULT, three, y);
- Term diff = d_solver->mkTerm(MINUS, y, x);
- // Formulas
- Term x_geq_3y = d_solver->mkTerm(GEQ, x, three_y);
- Term x_leq_y = d_solver->mkTerm(LEQ, x, y);
- Term neg2_lt_x = d_solver->mkTerm(LT, neg2, x);
- // Assertions
- Term assertions = d_solver->mkTerm(AND, x_geq_3y, x_leq_y, neg2_lt_x);
-
- TS_ASSERT_THROWS_NOTHING(d_solver->checkValid());
- d_solver->assertFormula(assertions);
- TS_ASSERT_THROWS_NOTHING(d_solver->checkValid());
-}
-
-void SolverBlack::testCheckValidAssuming1()
-{
- d_solver->setOption("incremental", "false");
- TS_ASSERT_THROWS_NOTHING(d_solver->checkValidAssuming(d_solver->mkTrue()));
- TS_ASSERT_THROWS(d_solver->checkValidAssuming(d_solver->mkTrue()),
- CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(d_solver->checkEntailed(d_solver->mkTrue()));
+ TS_ASSERT_THROWS(d_solver->checkEntailed(Term()), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(d_solver->checkEntailed(d_solver->mkTrue()));
+ TS_ASSERT_THROWS_NOTHING(d_solver->checkEntailed(z));
}
-void SolverBlack::testCheckValidAssuming2()
+void SolverBlack::testCheckEntailed2()
{
d_solver->setOption("incremental", "true");
@@ -1185,15 +1173,15 @@ void SolverBlack::testCheckValidAssuming2()
p_f_y // p(f(y))
});
- TS_ASSERT_THROWS_NOTHING(d_solver->checkValidAssuming(d_solver->mkTrue()));
+ TS_ASSERT_THROWS_NOTHING(d_solver->checkEntailed(d_solver->mkTrue()));
d_solver->assertFormula(assertions);
TS_ASSERT_THROWS_NOTHING(
- d_solver->checkValidAssuming(d_solver->mkTerm(DISTINCT, x, y)));
- TS_ASSERT_THROWS_NOTHING(d_solver->checkValidAssuming(
+ d_solver->checkEntailed(d_solver->mkTerm(DISTINCT, x, y)));
+ TS_ASSERT_THROWS_NOTHING(d_solver->checkEntailed(
{d_solver->mkFalse(), d_solver->mkTerm(DISTINCT, x, y)}));
- TS_ASSERT_THROWS(d_solver->checkValidAssuming(n), CVC4ApiException&);
+ TS_ASSERT_THROWS(d_solver->checkEntailed(n), CVC4ApiException&);
TS_ASSERT_THROWS(
- d_solver->checkValidAssuming({n, d_solver->mkTerm(DISTINCT, x, y)}),
+ d_solver->checkEntailed({n, d_solver->mkTerm(DISTINCT, x, y)}),
CVC4ApiException&);
}
diff --git a/test/unit/expr/CMakeLists.txt b/test/unit/expr/CMakeLists.txt
index d487bf560..438b7f7b6 100644
--- a/test/unit/expr/CMakeLists.txt
+++ b/test/unit/expr/CMakeLists.txt
@@ -13,6 +13,7 @@ cvc4_add_unit_test_black(node_builder_black expr)
cvc4_add_unit_test_black(node_manager_black expr)
cvc4_add_unit_test_white(node_manager_white expr)
cvc4_add_unit_test_black(node_self_iterator_black expr)
+cvc4_add_unit_test_black(node_traversal_black expr)
cvc4_add_unit_test_white(node_white expr)
cvc4_add_unit_test_black(symbol_table_black expr)
cvc4_add_unit_test_black(type_cardinality_public expr)
diff --git a/test/unit/expr/node_traversal_black.h b/test/unit/expr/node_traversal_black.h
new file mode 100644
index 000000000..b4a7c449c
--- /dev/null
+++ b/test/unit/expr/node_traversal_black.h
@@ -0,0 +1,281 @@
+/********************* */
+/*! \file node_traversal_black.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Alex Ozdemir
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Black box testing of node traversal iterators.
+ **/
+
+#include <cxxtest/TestSuite.h>
+
+// Used in some of the tests
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "expr/expr_manager.h"
+#include "expr/node.h"
+#include "expr/node_builder.h"
+#include "expr/node_manager.h"
+#include "expr/node_traversal.h"
+#include "expr/node_value.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace std;
+
+class NodePostorderTraversalBlack : public CxxTest::TestSuite
+{
+ private:
+ NodeManager* d_nodeManager;
+ NodeManagerScope* d_scope;
+
+ public:
+ void setUp() override
+ {
+ d_nodeManager = new NodeManager(NULL);
+ d_scope = new NodeManagerScope(d_nodeManager);
+ }
+
+ void tearDown() override
+ {
+ delete d_scope;
+ delete d_nodeManager;
+ }
+
+ void testPreincrementIteration()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ auto traversal = NodeDfsIterable(cnd).inPostorder();
+ NodeDfsIterator i = traversal.begin();
+ NodeDfsIterator end = traversal.end();
+ TS_ASSERT_EQUALS(*i, tb);
+ TS_ASSERT_DIFFERS(i, end);
+ ++i;
+ TS_ASSERT_EQUALS(*i, eb);
+ TS_ASSERT_DIFFERS(i, end);
+ ++i;
+ TS_ASSERT_EQUALS(*i, cnd);
+ TS_ASSERT_DIFFERS(i, end);
+ ++i;
+ TS_ASSERT_EQUALS(i, end);
+ }
+
+ void testPostincrementIteration()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ auto traversal = NodeDfsIterable(cnd).inPostorder();
+ NodeDfsIterator i = traversal.begin();
+ NodeDfsIterator end = traversal.end();
+ TS_ASSERT_EQUALS(*(i++), tb);
+ TS_ASSERT_EQUALS(*(i++), eb);
+ TS_ASSERT_EQUALS(*(i++), cnd);
+ TS_ASSERT_EQUALS(i, end);
+ }
+
+ void testPostorderIsDefault()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ auto traversal = NodeDfsIterable(cnd);
+ NodeDfsIterator i = traversal.begin();
+ NodeDfsIterator end = traversal.end();
+ TS_ASSERT_EQUALS(*i, tb);
+ TS_ASSERT_DIFFERS(i, end);
+ }
+
+ void testRangeForLoop()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ size_t count = 0;
+ for (auto i : NodeDfsIterable(cnd).inPostorder())
+ {
+ ++count;
+ }
+ TS_ASSERT_EQUALS(count, 3);
+ }
+
+ void testCountIfWithLoop()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ size_t count = 0;
+ for (auto i : NodeDfsIterable(cnd).inPostorder())
+ {
+ if (i.isConst())
+ {
+ ++count;
+ }
+ }
+ TS_ASSERT_EQUALS(count, 2);
+ }
+
+ void testStlCountIf()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+ Node top = d_nodeManager->mkNode(XOR, cnd, cnd);
+
+ auto traversal = NodeDfsIterable(top).inPostorder();
+
+ size_t count = std::count_if(traversal.begin(),
+ traversal.end(),
+ [](TNode n) { return n.isConst(); });
+ TS_ASSERT_EQUALS(count, 2);
+ }
+
+ void testStlCopy()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+ Node top = d_nodeManager->mkNode(XOR, cnd, cnd);
+ std::vector<TNode> expected = {tb, eb, cnd, top};
+
+ auto traversal = NodeDfsIterable(top).inPostorder();
+
+ std::vector<TNode> actual;
+ std::copy(traversal.begin(), traversal.end(), std::back_inserter(actual));
+ TS_ASSERT_EQUALS(actual, expected);
+ }
+};
+
+class NodePreorderTraversalBlack : public CxxTest::TestSuite
+{
+ private:
+ NodeManager* d_nodeManager;
+ NodeManagerScope* d_scope;
+
+ public:
+ void setUp() override
+ {
+ d_nodeManager = new NodeManager(NULL);
+ d_scope = new NodeManagerScope(d_nodeManager);
+ }
+
+ void tearDown() override
+ {
+ delete d_scope;
+ delete d_nodeManager;
+ }
+
+ void testPreincrementIteration()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ auto traversal = NodeDfsIterable(cnd).inPreorder();
+ NodeDfsIterator i = traversal.begin();
+ NodeDfsIterator end = traversal.end();
+ TS_ASSERT_EQUALS(*i, cnd);
+ TS_ASSERT_DIFFERS(i, end);
+ ++i;
+ TS_ASSERT_EQUALS(*i, tb);
+ TS_ASSERT_DIFFERS(i, end);
+ ++i;
+ TS_ASSERT_EQUALS(*i, eb);
+ TS_ASSERT_DIFFERS(i, end);
+ ++i;
+ TS_ASSERT_EQUALS(i, end);
+ }
+
+ void testPostincrementIteration()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ auto traversal = NodeDfsIterable(cnd).inPreorder();
+ NodeDfsIterator i = traversal.begin();
+ NodeDfsIterator end = traversal.end();
+ TS_ASSERT_EQUALS(*(i++), cnd);
+ TS_ASSERT_EQUALS(*(i++), tb);
+ TS_ASSERT_EQUALS(*(i++), eb);
+ TS_ASSERT_EQUALS(i, end);
+ }
+
+ void testRangeForLoop()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ size_t count = 0;
+ for (auto i : NodeDfsIterable(cnd).inPreorder())
+ {
+ ++count;
+ }
+ TS_ASSERT_EQUALS(count, 3);
+ }
+
+ void testCountIfWithLoop()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+
+ size_t count = 0;
+ for (auto i : NodeDfsIterable(cnd).inPreorder())
+ {
+ if (i.isConst())
+ {
+ ++count;
+ }
+ }
+ TS_ASSERT_EQUALS(count, 2);
+ }
+
+ void testStlCountIf()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+ Node top = d_nodeManager->mkNode(XOR, cnd, cnd);
+
+ auto traversal = NodeDfsIterable(top).inPreorder();
+
+ size_t count = std::count_if(traversal.begin(),
+ traversal.end(),
+ [](TNode n) { return n.isConst(); });
+ TS_ASSERT_EQUALS(count, 2);
+ }
+
+ void testStlCopy()
+ {
+ Node tb = d_nodeManager->mkConst(true);
+ Node eb = d_nodeManager->mkConst(false);
+ Node cnd = d_nodeManager->mkNode(XOR, tb, eb);
+ Node top = d_nodeManager->mkNode(XOR, cnd, cnd);
+ std::vector<TNode> expected = {top, cnd, tb, eb};
+
+ auto traversal = NodeDfsIterable(top).inPreorder();
+
+ std::vector<TNode> actual;
+ std::copy(traversal.begin(), traversal.end(), std::back_inserter(actual));
+ TS_ASSERT_EQUALS(actual, expected);
+ }
+};
diff --git a/test/unit/preprocessing/pass_bv_gauss_white.h b/test/unit/preprocessing/pass_bv_gauss_white.h
index 4037c7191..bd21ed69c 100644
--- a/test/unit/preprocessing/pass_bv_gauss_white.h
+++ b/test/unit/preprocessing/pass_bv_gauss_white.h
@@ -176,6 +176,7 @@ class TheoryBVGaussWhite : public CxxTest::TestSuite
d_nm = NodeManager::fromExprManager(d_em);
d_smt = new SmtEngine(d_em);
d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
d_zero = bv::utils::mkZero(16);
@@ -2373,7 +2374,7 @@ class TheoryBVGaussWhite : public CxxTest::TestSuite
AssertionPipeline apipe;
apipe.push_back(a);
- passes::BVGauss bgauss(nullptr);
+ passes::BVGauss bgauss(nullptr, "bv-gauss-unit");
std::unordered_map<Node, Node, NodeHashFunction> res;
PreprocessingPassResult pres = bgauss.applyInternal(&apipe);
TS_ASSERT (pres == PreprocessingPassResult::NO_CONFLICT);
@@ -2457,7 +2458,7 @@ class TheoryBVGaussWhite : public CxxTest::TestSuite
apipe.push_back(a);
apipe.push_back(eq4);
apipe.push_back(eq5);
- passes::BVGauss bgauss(nullptr);
+ passes::BVGauss bgauss(nullptr, "bv-gauss-unit");
std::unordered_map<Node, Node, NodeHashFunction> res;
PreprocessingPassResult pres = bgauss.applyInternal(&apipe);
TS_ASSERT (pres == PreprocessingPassResult::NO_CONFLICT);
@@ -2507,7 +2508,7 @@ class TheoryBVGaussWhite : public CxxTest::TestSuite
AssertionPipeline apipe;
apipe.push_back(eq1);
apipe.push_back(eq2);
- passes::BVGauss bgauss(nullptr);
+ passes::BVGauss bgauss(nullptr, "bv-gauss-unit");
std::unordered_map<Node, Node, NodeHashFunction> res;
PreprocessingPassResult pres = bgauss.applyInternal(&apipe);
TS_ASSERT (pres == PreprocessingPassResult::NO_CONFLICT);
diff --git a/test/unit/theory/evaluator_white.h b/test/unit/theory/evaluator_white.h
index c02aaaed8..547ce27cf 100644
--- a/test/unit/theory/evaluator_white.h
+++ b/test/unit/theory/evaluator_white.h
@@ -52,6 +52,7 @@ class TheoryEvaluatorWhite : public CxxTest::TestSuite
d_nm = NodeManager::fromExprManager(d_em);
d_smt = new SmtEngine(d_em);
d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
}
void tearDown() override
diff --git a/test/unit/theory/regexp_operation_black.h b/test/unit/theory/regexp_operation_black.h
index 81f5cf34a..826e14a31 100644
--- a/test/unit/theory/regexp_operation_black.h
+++ b/test/unit/theory/regexp_operation_black.h
@@ -45,6 +45,10 @@ class RegexpOperationBlack : public CxxTest::TestSuite
d_scope = new SmtScope(d_smt);
d_regExpOpr = new RegExpOpr();
+ // Ensure that the SMT engine is fully initialized (required for the
+ // rewriter)
+ d_smt->push();
+
d_nm = NodeManager::currentNM();
}
diff --git a/test/unit/theory/sequences_rewriter_white.h b/test/unit/theory/sequences_rewriter_white.h
index 200a36d0b..c823c0704 100644
--- a/test/unit/theory/sequences_rewriter_white.h
+++ b/test/unit/theory/sequences_rewriter_white.h
@@ -45,6 +45,7 @@ class SequencesRewriterWhite : public CxxTest::TestSuite
d_em = new ExprManager(opts);
d_smt = new SmtEngine(d_em);
d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
d_rewriter = new ExtendedRewriter(true);
d_nm = NodeManager::currentNM();
diff --git a/test/unit/theory/theory_black.h b/test/unit/theory/theory_black.h
index 8ae90c4c3..72b74a7b9 100644
--- a/test/unit/theory/theory_black.h
+++ b/test/unit/theory/theory_black.h
@@ -37,19 +37,15 @@ using namespace CVC4::theory;
using namespace CVC4::smt;
class TheoryBlack : public CxxTest::TestSuite {
-private:
-
- ExprManager* d_em;
- SmtEngine* d_smt;
- NodeManager* d_nm;
- SmtScope* d_scope;
-
public:
void setUp() override
{
d_em = new ExprManager();
d_smt = new SmtEngine(d_em);
d_scope = new SmtScope(d_smt);
+ // Ensure that the SMT engine is fully initialized (required for the
+ // rewriter)
+ d_smt->push();
d_nm = NodeManager::fromExprManager(d_em);
}
@@ -152,4 +148,9 @@ private:
}
+ private:
+ ExprManager* d_em;
+ SmtEngine* d_smt;
+ NodeManager* d_nm;
+ SmtScope* d_scope;
};
diff --git a/test/unit/theory/theory_bv_rewriter_white.h b/test/unit/theory/theory_bv_rewriter_white.h
index bf0ca73b3..b6348339b 100644
--- a/test/unit/theory/theory_bv_rewriter_white.h
+++ b/test/unit/theory/theory_bv_rewriter_white.h
@@ -43,6 +43,7 @@ class TheoryBvRewriterWhite : public CxxTest::TestSuite
d_em = new ExprManager(opts);
d_smt = new SmtEngine(d_em);
d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
d_nm = NodeManager::currentNM();
}
diff --git a/test/unit/theory/theory_engine_white.h b/test/unit/theory/theory_engine_white.h
index 5af670d5e..4a019ac08 100644
--- a/test/unit/theory/theory_engine_white.h
+++ b/test/unit/theory/theory_engine_white.h
@@ -38,6 +38,7 @@
#include "theory/rewriter.h"
#include "theory/theory.h"
#include "theory/theory_engine.h"
+#include "theory/theory_rewriter.h"
#include "theory/valuation.h"
#include "util/integer.h"
#include "util/proof.h"
@@ -91,118 +92,72 @@ struct RewriteItem {
bool d_topLevel;
};/* struct RewriteItem */
+class FakeTheoryRewriter : public TheoryRewriter
+{
+ public:
+ RewriteResponse preRewrite(TNode n) override
+ {
+ return RewriteResponse(REWRITE_DONE, n);
+ }
+
+ RewriteResponse postRewrite(TNode n) override
+ {
+ return RewriteResponse(REWRITE_DONE, n);
+ }
+};
+
/**
- * Fake Theory interface. Looks like a Theory, but really all it does is note when and
- * how rewriting behavior is requested.
+ * Fake Theory interface. Looks like a Theory, but really all it does is note
+ * when and how rewriting behavior is requested.
*/
-template<TheoryId theoryId>
-class FakeTheory : public Theory {
+template <TheoryId theoryId>
+class FakeTheory : public Theory
+{
/**
- * This fake theory class is equally useful for bool, uf, arith, etc. It keeps an
- * identifier to identify itself.
+ * This fake theory class is equally useful for bool, uf, arith, etc. It
+ * keeps an identifier to identify itself.
*/
std::string d_id;
/**
- * The expected sequence of rewrite calls. Filled by FakeTheory::expect() and consumed
- * by FakeTheory::preRewrite() and FakeTheory::postRewrite().
+ * The expected sequence of rewrite calls. Filled by FakeTheory::expect() and
+ * consumed by FakeTheory::preRewrite() and FakeTheory::postRewrite().
*/
// static std::deque<RewriteItem> s_expected;
-public:
- FakeTheory(context::Context* ctxt, context::UserContext* uctxt, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(theoryId, ctxt, uctxt, out, valuation, logicInfo)
- { }
-
- /** Register an expected rewrite call */
- static void expect(RewriteType type, FakeTheory* thy, TNode n, bool topLevel)
- throw()
+ public:
+ FakeTheory(context::Context* ctxt,
+ context::UserContext* uctxt,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo)
+ : Theory(theoryId, ctxt, uctxt, out, valuation, logicInfo)
{
- RewriteItem item = { type, thy, n, topLevel };
- //s_expected.push_back(item);
}
- /**
- * Returns whether the expected queue is empty. This is done after a call into
- * the rewriter to ensure that the actual set of observed rewrite calls completed
- * the sequence of expected rewrite calls.
- */
- static bool nothingMoreExpected() throw() {
- return true; // s_expected.empty();
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter() override
+ {
+ return std::unique_ptr<TheoryRewriter>(new FakeTheoryRewriter());
}
- /**
- * Overrides Theory::preRewrite(). This "fake theory" version ensures that
- * this actual, observed pre-rewrite call matches the next "expected" call set up
- * by the test.
- */
- RewriteResponse preRewrite(TNode n, bool topLevel) {
-// if(false) { //s_expected.empty()) {
-// cout << std::endl
-// << "didn't expect anything more, but got" << std::endl
-// << " PRE " << topLevel << " " << identify() << " " << n
-// << std::endl;
-// }
-// TS_ASSERT(!s_expected.empty());
-//
-// RewriteItem expected = s_expected.front();
-// s_expected.pop_front();
-//
-// if(expected.d_type != PRE ||
-//// expected.d_theory != this ||
-// expected.d_node != n ||
-// expected.d_topLevel != topLevel) {
-// cout << std::endl
-// << "HAVE PRE " << topLevel << " " << identify() << " " << n
-// << std::endl
-// << "WANT " << (expected.d_type == PRE ? "PRE " : "POST ")
-// // << expected.d_topLevel << " " << expected.d_theory->identify()
-// << " " << expected.d_node << std::endl << std::endl;
-// }
-//
-// TS_ASSERT_EQUALS(expected.d_type, PRE);
-//// TS_ASSERT_EQUALS(expected.d_theory, this);
-// TS_ASSERT_EQUALS(expected.d_node, n);
-// TS_ASSERT_EQUALS(expected.d_topLevel, topLevel);
-
- return RewriteResponse(REWRITE_DONE, n);
+ /** Register an expected rewrite call */
+ static void expect(RewriteType type,
+ FakeTheory* thy,
+ TNode n,
+ bool topLevel) throw()
+ {
+ RewriteItem item = {type, thy, n, topLevel};
+ // s_expected.push_back(item);
}
/**
- * Overrides Theory::postRewrite(). This "fake theory" version ensures that
- * this actual, observed post-rewrite call matches the next "expected" call set up
- * by the test.
+ * Returns whether the expected queue is empty. This is done after a call
+ * into the rewriter to ensure that the actual set of observed rewrite calls
+ * completed the sequence of expected rewrite calls.
*/
- RewriteResponse postRewrite(TNode n, bool topLevel) {
-// if(s_expected.empty()) {
-// cout << std::endl
-// << "didn't expect anything more, but got" << std::endl
-// << " POST " << topLevel << " " << identify() << " " << n
-// << std::endl;
-// }
-// TS_ASSERT(!s_expected.empty());
-//
-// RewriteItem expected = s_expected.front();
-// s_expected.pop_front();
-//
-// if(expected.d_type != POST ||
-//// expected.d_theory != this ||
-// expected.d_node != n ||
-// expected.d_topLevel != topLevel) {
-// cout << std::endl
-// << "HAVE POST " << topLevel << " " << identify() << " " << n
-// << std::endl
-// << "WANT " << (expected.d_type == PRE ? "PRE " : "POST ")
-//// << expected.d_topLevel << " " << expected.d_theory->identify()
-// << " " << expected.d_node << std::endl << std::endl;
-// }
-//
-// TS_ASSERT_EQUALS(expected.d_type, POST);
-// TS_ASSERT_EQUALS(expected.d_theory, this);
-// TS_ASSERT_EQUALS(expected.d_node, n);
-// TS_ASSERT_EQUALS(expected.d_topLevel, topLevel);
-
- return RewriteResponse(REWRITE_DONE, n);
+ static bool nothingMoreExpected() throw()
+ {
+ return true; // s_expected.empty();
}
std::string identify() const override {
@@ -221,8 +176,7 @@ public:
return Node::null();
}
Node getValue(TNode n) { return Node::null(); }
-};/* class FakeTheory */
-
+}; /* class FakeTheory */
/* definition of the s_expected static field in FakeTheory; see above */
// std::deque<RewriteItem> FakeTheory::s_expected;
diff --git a/test/unit/theory/theory_quantifiers_bv_instantiator_white.h b/test/unit/theory/theory_quantifiers_bv_instantiator_white.h
index 0fa7a3f82..7c37b1a85 100644
--- a/test/unit/theory/theory_quantifiers_bv_instantiator_white.h
+++ b/test/unit/theory/theory_quantifiers_bv_instantiator_white.h
@@ -65,6 +65,7 @@ void BvInstantiatorWhite::setUp()
d_nm = NodeManager::fromExprManager(d_em);
d_smt = new SmtEngine(d_em);
d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
}
void BvInstantiatorWhite::tearDown()
diff --git a/test/unit/theory/theory_sets_type_enumerator_white.h b/test/unit/theory/theory_sets_type_enumerator_white.h
index 3b5016fad..0ece5a056 100644
--- a/test/unit/theory/theory_sets_type_enumerator_white.h
+++ b/test/unit/theory/theory_sets_type_enumerator_white.h
@@ -18,9 +18,12 @@
#include <cxxtest/TestSuite.h>
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "theory/sets/theory_sets_type_enumerator.h"
using namespace CVC4;
+using namespace CVC4::smt;
using namespace CVC4::theory;
using namespace CVC4::kind;
using namespace CVC4::theory::sets;
@@ -28,21 +31,20 @@ using namespace std;
class SetEnumeratorWhite : public CxxTest::TestSuite
{
- ExprManager* d_em;
- NodeManager* d_nm;
- NodeManagerScope* d_scope;
-
public:
void setUp() override
{
d_em = new ExprManager();
+ d_smt = new SmtEngine(d_em);
d_nm = NodeManager::fromExprManager(d_em);
- d_scope = new NodeManagerScope(d_nm);
+ d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
}
void tearDown() override
{
delete d_scope;
+ delete d_smt;
delete d_em;
}
@@ -68,8 +70,9 @@ class SetEnumeratorWhite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(expected2, actual2);
TS_ASSERT(!setEnumerator.isFinished());
- Node actual3 = *++setEnumerator;
- Node expected3 = d_nm->mkNode(Kind::UNION, expected1, expected2);
+ Node actual3 = Rewriter::rewrite(*++setEnumerator);
+ Node expected3 =
+ Rewriter::rewrite(d_nm->mkNode(Kind::UNION, expected1, expected2));
TS_ASSERT_EQUALS(expected3, actual3);
TS_ASSERT(!setEnumerator.isFinished());
@@ -301,4 +304,9 @@ class SetEnumeratorWhite : public CxxTest::TestSuite
TS_ASSERT(setEnumerator.isFinished());
}
+ private:
+ ExprManager* d_em;
+ SmtEngine* d_smt;
+ NodeManager* d_nm;
+ SmtScope* d_scope;
}; /* class SetEnumeratorWhite */
diff --git a/test/unit/theory/theory_strings_skolem_cache_black.h b/test/unit/theory/theory_strings_skolem_cache_black.h
index 34e8d88c6..8f41153f3 100644
--- a/test/unit/theory/theory_strings_skolem_cache_black.h
+++ b/test/unit/theory/theory_strings_skolem_cache_black.h
@@ -16,13 +16,17 @@
#include <memory>
+#include "expr/expr_manager.h"
#include "expr/node.h"
#include "expr/node_manager.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "theory/strings/skolem_cache.h"
#include "util/rational.h"
-#include "util/regexp.h"
+#include "util/string.h"
using namespace CVC4;
+using namespace CVC4::smt;
using namespace CVC4::theory::strings;
class TheoryStringsSkolemCacheBlack : public CxxTest::TestSuite
@@ -30,8 +34,14 @@ class TheoryStringsSkolemCacheBlack : public CxxTest::TestSuite
public:
void setUp() override
{
- d_nm.reset(new NodeManager(nullptr));
- d_scope.reset(new NodeManagerScope(d_nm.get()));
+ d_em.reset(new ExprManager());
+ d_smt.reset(new SmtEngine(d_em.get()));
+ d_scope.reset(new SmtScope(d_smt.get()));
+ // Ensure that the SMT engine is fully initialized (required for the
+ // rewriter)
+ d_smt->push();
+
+ d_nm = NodeManager::fromExprManager(d_em.get());
}
void tearDown() override {}
@@ -87,6 +97,8 @@ class TheoryStringsSkolemCacheBlack : public CxxTest::TestSuite
}
private:
- std::unique_ptr<NodeManager> d_nm;
- std::unique_ptr<NodeManagerScope> d_scope;
+ std::unique_ptr<ExprManager> d_em;
+ std::unique_ptr<SmtEngine> d_smt;
+ NodeManager* d_nm;
+ std::unique_ptr<SmtScope> d_scope;
};
diff --git a/test/unit/theory/theory_white.h b/test/unit/theory/theory_white.h
index 0dd52be8c..eb43e00cb 100644
--- a/test/unit/theory/theory_white.h
+++ b/test/unit/theory/theory_white.h
@@ -93,7 +93,7 @@ class TestOutputChannel : public OutputChannel {
};
class DummyTheory : public Theory {
-public:
+ public:
set<Node> d_registered;
vector<Node> d_getSequence;
@@ -102,6 +102,11 @@ public:
: Theory(theory::THEORY_BUILTIN, ctxt, uctxt, out, valuation, logicInfo)
{}
+ std::unique_ptr<TheoryRewriter> mkTheoryRewriter()
+ {
+ return std::unique_ptr<TheoryRewriter>();
+ }
+
void registerTerm(TNode n) {
// check that we registerTerm() a term only once
TS_ASSERT(d_registered.find(n) == d_registered.end());
diff --git a/test/unit/theory/type_enumerator_white.h b/test/unit/theory/type_enumerator_white.h
index da915b7ee..58dadd27a 100644
--- a/test/unit/theory/type_enumerator_white.h
+++ b/test/unit/theory/type_enumerator_white.h
@@ -25,30 +25,32 @@
#include "expr/node_manager.h"
#include "expr/type_node.h"
#include "options/language.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "theory/type_enumerator.h"
using namespace CVC4;
+using namespace CVC4::smt;
using namespace CVC4::theory;
using namespace CVC4::kind;
using namespace std;
class TypeEnumeratorWhite : public CxxTest::TestSuite {
- ExprManager* d_em;
- NodeManager* d_nm;
- NodeManagerScope* d_scope;
-
public:
void setUp() override
{
d_em = new ExprManager();
+ d_smt = new SmtEngine(d_em);
d_nm = NodeManager::fromExprManager(d_em);
- d_scope = new NodeManagerScope(d_nm);
+ d_scope = new SmtScope(d_smt);
+ d_smt->finalOptionsAreSet();
}
void tearDown() override
{
delete d_scope;
+ delete d_smt;
delete d_em;
}
@@ -272,4 +274,9 @@ class TypeEnumeratorWhite : public CxxTest::TestSuite {
TS_ASSERT_THROWS(*++te, NoMoreValuesException&);
}
+ private:
+ ExprManager* d_em;
+ SmtEngine* d_smt;
+ NodeManager* d_nm;
+ SmtScope* d_scope;
};/* class TypeEnumeratorWhite */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback