summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.project2
-rw-r--r--INSTALL2
-rw-r--r--Makefile1
-rw-r--r--Makefile.am9
-rw-r--r--NEWS26
-rw-r--r--README2
-rw-r--r--RELEASE-NOTES16
-rw-r--r--THANKS3
-rw-r--r--config/bindings.m439
-rw-r--r--config/cvc4.m439
-rw-r--r--config/doxygen.cfg2
-rw-r--r--config/glpk.m418
-rw-r--r--configure.ac40
-rwxr-xr-xcontrib/get-antlr-3.434
-rwxr-xr-xcontrib/get-bug-attachments4
-rwxr-xr-xcontrib/run-script-casc24-fnt38
-rwxr-xr-xcontrib/run-script-casc24-fnt-no-models36
-rwxr-xr-xcontrib/run-script-casc24-fof37
-rwxr-xr-xcontrib/run-script-smteval201332
-rw-r--r--contrib/theoryskel/README.WHATS-NEXT9
-rw-r--r--doc/SmtEngine.3cvc_template.in4
-rw-r--r--doc/cvc4.1_template.in4
-rw-r--r--doc/cvc4.5.in2
-rw-r--r--doc/libcvc4compat.3.in2
-rw-r--r--doc/libcvc4parser.3.in2
-rw-r--r--doc/options.3cvc_template.in4
-rw-r--r--examples/api/java/CVC4Streams.java59
-rw-r--r--examples/api/java/Makefile.am2
-rw-r--r--library_versions5
-rw-r--r--src/Makefile.am46
-rw-r--r--src/bindings/Makefile.am6
-rw-r--r--src/bindings/compat/java/include/cvc3/JniUtils.h2
-rw-r--r--src/compat/cvc3_compat.cpp27
-rw-r--r--src/cvc4.i5
-rw-r--r--src/decision/Makefile.am4
-rw-r--r--src/decision/decision_engine.cpp38
-rw-r--r--src/decision/decision_engine.h7
-rw-r--r--src/decision/justification_heuristic.cpp11
-rw-r--r--src/decision/options10
-rw-r--r--src/decision/options_handlers.h50
-rw-r--r--src/decision/relevancy.cpp379
-rw-r--r--src/decision/relevancy.h421
-rw-r--r--src/expr/attribute.h18
-rw-r--r--src/expr/attribute_internals.h28
-rw-r--r--src/expr/command.cpp217
-rw-r--r--src/expr/command.h60
-rw-r--r--src/expr/expr.i4
-rw-r--r--src/expr/expr_manager.i4
-rw-r--r--src/expr/expr_manager_template.cpp41
-rw-r--r--src/expr/expr_manager_template.h86
-rw-r--r--src/expr/expr_template.cpp13
-rw-r--r--src/expr/expr_template.h6
-rw-r--r--src/expr/metakind_template.h45
-rwxr-xr-xsrc/expr/mkmetakind9
-rw-r--r--src/expr/node.h12
-rw-r--r--src/expr/node_builder.h41
-rw-r--r--src/expr/node_manager.h174
-rw-r--r--src/expr/node_value.h10
-rw-r--r--src/expr/type.cpp4
-rw-r--r--src/expr/type.h3
-rw-r--r--src/expr/type.i4
-rw-r--r--src/expr/type_node.cpp11
-rw-r--r--src/expr/type_node.h13
-rw-r--r--src/include/cvc4_private_library.h2
-rw-r--r--src/include/cvc4_public.h3
-rw-r--r--src/lib/clock_gettime.h6
-rw-r--r--src/main/command_executor.cpp32
-rw-r--r--src/main/command_executor.h3
-rw-r--r--src/main/command_executor_portfolio.cpp17
-rw-r--r--src/main/driver_unified.cpp10
-rw-r--r--src/main/interactive_shell.cpp7
-rw-r--r--src/main/main.cpp8
-rw-r--r--src/main/main.h2
-rw-r--r--src/main/options4
-rw-r--r--src/main/portfolio.cpp2
-rw-r--r--src/main/portfolio_util.h1
-rw-r--r--src/main/util.cpp11
-rw-r--r--src/options/Makefile.am12
-rw-r--r--src/options/base_options5
-rwxr-xr-xsrc/options/mkoptions88
-rw-r--r--src/options/options.h22
-rw-r--r--src/options/options_template.cpp105
-rw-r--r--src/parser/antlr_input.cpp11
-rw-r--r--src/parser/antlr_input.h12
-rw-r--r--src/parser/antlr_line_buffered_input.cpp9
-rw-r--r--src/parser/bounded_token_buffer.cpp2
-rw-r--r--src/parser/cvc/Cvc.g60
-rw-r--r--src/parser/cvc/Makefile.am2
-rw-r--r--src/parser/options4
-rw-r--r--src/parser/parser.cpp63
-rw-r--r--src/parser/parser.h82
-rw-r--r--src/parser/parser_builder.cpp15
-rw-r--r--src/parser/parser_builder.h10
-rw-r--r--src/parser/smt1/smt1.cpp7
-rw-r--r--src/parser/smt1/smt1.h4
-rw-r--r--src/parser/smt2/Smt2.g283
-rw-r--r--src/parser/smt2/smt2.cpp229
-rw-r--r--src/parser/smt2/smt2.h32
-rw-r--r--src/parser/tptp/Tptp.g643
-rw-r--r--src/parser/tptp/tptp.cpp103
-rw-r--r--src/parser/tptp/tptp.h93
-rw-r--r--src/parser/tptp/tptp_input.cpp4
-rw-r--r--src/parser/tptp/tptp_input.h2
-rw-r--r--src/printer/Makefile.am4
-rw-r--r--src/printer/ast/ast_printer.cpp4
-rw-r--r--src/printer/ast/ast_printer.h4
-rw-r--r--src/printer/cvc/cvc_printer.cpp4
-rw-r--r--src/printer/cvc/cvc_printer.h2
-rw-r--r--src/printer/printer.cpp7
-rw-r--r--src/printer/printer.h9
-rw-r--r--src/printer/smt1/smt1_printer.cpp4
-rw-r--r--src/printer/smt1/smt1_printer.h4
-rw-r--r--src/printer/smt2/smt2_printer.cpp101
-rw-r--r--src/printer/smt2/smt2_printer.h4
-rw-r--r--src/printer/tptp/tptp_printer.cpp83
-rw-r--r--src/printer/tptp/tptp_printer.h46
-rw-r--r--src/proof/cnf_proof.cpp2
-rw-r--r--src/proof/cnf_proof.h2
-rw-r--r--src/proof/sat_proof.cpp57
-rw-r--r--src/proof/sat_proof.h31
-rw-r--r--src/prop/cnf_stream.cpp6
-rw-r--r--src/prop/minisat/core/Solver.cc33
-rw-r--r--src/prop/minisat/core/Solver.h4
-rw-r--r--src/prop/minisat/minisat.h5
-rw-r--r--src/prop/minisat/mtl/Vec.h2
-rw-r--r--src/prop/minisat/simp/SimpSolver.cc8
-rw-r--r--src/prop/options4
-rw-r--r--src/prop/prop_engine.cpp4
-rw-r--r--src/smt/boolean_terms.cpp46
-rw-r--r--src/smt/options6
-rw-r--r--src/smt/options_handlers.h16
-rw-r--r--src/smt/smt_engine.cpp735
-rw-r--r--src/smt/smt_engine.h34
-rw-r--r--src/smt/smt_options_template.cpp65
-rw-r--r--src/theory/Makefile.am10
-rw-r--r--src/theory/arith/Makefile.am4
-rw-r--r--src/theory/arith/approx_simplex.cpp336
-rw-r--r--src/theory/arith/approx_simplex.h11
-rw-r--r--src/theory/arith/arith_rewriter.cpp95
-rw-r--r--src/theory/arith/arith_static_learner.h1
-rw-r--r--src/theory/arith/attempt_solution_simplex.cpp135
-rw-r--r--src/theory/arith/attempt_solution_simplex.h (renamed from src/theory/arith/pure_update_simplex.h)53
-rw-r--r--src/theory/arith/bound_counts.h242
-rw-r--r--src/theory/arith/callbacks.cpp4
-rw-r--r--src/theory/arith/callbacks.h16
-rw-r--r--src/theory/arith/constraint.cpp22
-rw-r--r--src/theory/arith/constraint.h2
-rw-r--r--src/theory/arith/dual_simplex.cpp37
-rw-r--r--src/theory/arith/error_set.cpp12
-rw-r--r--src/theory/arith/error_set.h16
-rw-r--r--src/theory/arith/fc_simplex.cpp17
-rw-r--r--src/theory/arith/kinds26
-rw-r--r--src/theory/arith/linear_equality.cpp572
-rw-r--r--src/theory/arith/linear_equality.h205
-rw-r--r--src/theory/arith/matrix.cpp2
-rw-r--r--src/theory/arith/matrix.h6
-rw-r--r--src/theory/arith/normal_form.cpp35
-rw-r--r--src/theory/arith/normal_form.h14
-rw-r--r--src/theory/arith/options24
-rw-r--r--src/theory/arith/partial_model.cpp217
-rw-r--r--src/theory/arith/partial_model.h115
-rw-r--r--src/theory/arith/pure_update_simplex.cpp261
-rw-r--r--src/theory/arith/simplex-converge.cpp1674
-rw-r--r--src/theory/arith/simplex-converge.h531
-rw-r--r--src/theory/arith/simplex.cpp17
-rw-r--r--src/theory/arith/simplex.h4
-rw-r--r--src/theory/arith/simplex_update.h2
-rw-r--r--src/theory/arith/soi_simplex.cpp252
-rw-r--r--src/theory/arith/soi_simplex.h13
-rw-r--r--src/theory/arith/tableau.cpp2
-rw-r--r--src/theory/arith/tableau.h6
-rw-r--r--src/theory/arith/theory_arith.cpp5
-rw-r--r--src/theory/arith/theory_arith.h3
-rw-r--r--src/theory/arith/theory_arith_private.cpp724
-rw-r--r--src/theory/arith/theory_arith_private.h41
-rw-r--r--src/theory/arith/theory_arith_type_rules.h59
-rw-r--r--src/theory/arrays/Makefile.am4
-rw-r--r--src/theory/arrays/theory_arrays.cpp79
-rw-r--r--src/theory/arrays/theory_arrays_model.cpp65
-rw-r--r--src/theory/arrays/theory_arrays_model.h58
-rw-r--r--src/theory/arrays/theory_arrays_rewriter.h14
-rw-r--r--src/theory/atom_requests.cpp62
-rw-r--r--src/theory/atom_requests.h107
-rw-r--r--src/theory/booleans/theory_bool.cpp1
-rw-r--r--src/theory/builtin/kinds25
-rw-r--r--src/theory/builtin/theory_builtin_rewriter.cpp3
-rw-r--r--src/theory/builtin/theory_builtin_type_rules.h16
-rw-r--r--src/theory/bv/bitblaster.cpp196
-rw-r--r--src/theory/bv/bitblaster.h93
-rw-r--r--src/theory/bv/bv_subtheory.h29
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp17
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h10
-rw-r--r--src/theory/bv/bv_subtheory_core.cpp203
-rw-r--r--src/theory/bv/bv_subtheory_core.h28
-rw-r--r--src/theory/bv/bv_subtheory_inequality.cpp87
-rw-r--r--src/theory/bv/bv_subtheory_inequality.h30
-rw-r--r--src/theory/bv/kinds11
-rw-r--r--src/theory/bv/options6
-rw-r--r--src/theory/bv/theory_bv.cpp72
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules.h20
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h10
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h51
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_simplification.h17
-rw-r--r--src/theory/bv/theory_bv_rewriter.cpp196
-rw-r--r--src/theory/bv/theory_bv_rewriter.h3
-rw-r--r--src/theory/bv/theory_bv_type_rules.h28
-rw-r--r--src/theory/bv/theory_bv_utils.h2
-rw-r--r--src/theory/datatypes/datatypes_rewriter.h11
-rw-r--r--src/theory/datatypes/kinds4
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp156
-rw-r--r--src/theory/idl/Makefile4
-rw-r--r--src/theory/idl/Makefile.am19
-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.cpp64
-rw-r--r--src/theory/idl/idl_model.h84
-rw-r--r--src/theory/idl/kinds8
-rw-r--r--src/theory/idl/options12
-rw-r--r--src/theory/idl/theory_idl.cpp143
-rw-r--r--src/theory/idl/theory_idl.h63
-rw-r--r--src/theory/ite_simplifier.cpp4
-rw-r--r--src/theory/ite_simplifier.h6
-rw-r--r--src/theory/logic_info.cpp28
-rw-r--r--src/theory/logic_info.h4
-rw-r--r--src/theory/model.cpp29
-rw-r--r--src/theory/options4
-rw-r--r--src/theory/output_channel.h7
-rw-r--r--src/theory/quantifiers/Makefile.am17
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp372
-rw-r--r--src/theory/quantifiers/bounded_integers.h127
-rw-r--r--src/theory/quantifiers/candidate_generator.cpp30
-rw-r--r--src/theory/quantifiers/candidate_generator.h42
-rw-r--r--src/theory/quantifiers/first_order_model.cpp254
-rw-r--r--src/theory/quantifiers/first_order_model.h106
-rw-r--r--src/theory/quantifiers/first_order_reasoning.cpp171
-rw-r--r--src/theory/quantifiers/first_order_reasoning.h45
-rw-r--r--src/theory/quantifiers/full_model_check.cpp1409
-rw-r--r--src/theory/quantifiers/full_model_check.h160
-rw-r--r--src/theory/quantifiers/inst_gen.cpp10
-rw-r--r--src/theory/quantifiers/inst_match.cpp21
-rw-r--r--src/theory/quantifiers/inst_match.h3
-rw-r--r--src/theory/quantifiers/inst_match_generator.cpp224
-rw-r--r--src/theory/quantifiers/inst_match_generator.h9
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.cpp285
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.h14
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.cpp4
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp17
-rw-r--r--src/theory/quantifiers/model_builder.cpp368
-rw-r--r--src/theory/quantifiers/model_builder.h90
-rw-r--r--src/theory/quantifiers/model_engine.cpp232
-rw-r--r--src/theory/quantifiers/model_engine.h34
-rw-r--r--src/theory/quantifiers/options31
-rw-r--r--src/theory/quantifiers/quant_util.cpp102
-rw-r--r--src/theory/quantifiers/quant_util.h12
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.cpp4
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.h4
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp8
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.cpp268
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/relevant_domain.h32
-rwxr-xr-xsrc/theory/quantifiers/rewrite_engine.cpp184
-rwxr-xr-xsrc/theory/quantifiers/rewrite_engine.h54
-rwxr-xr-xsrc/theory/quantifiers/symmetry_breaking.cpp314
-rwxr-xr-xsrc/theory/quantifiers/symmetry_breaking.h118
-rw-r--r--src/theory/quantifiers/term_database.cpp122
-rw-r--r--src/theory/quantifiers/term_database.h28
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp8
-rw-r--r--src/theory/quantifiers/trigger.cpp145
-rw-r--r--src/theory/quantifiers/trigger.h3
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers_engine.cpp89
-rw-r--r--src/theory/quantifiers_engine.h24
-rw-r--r--src/theory/rep_set.cpp198
-rw-r--r--src/theory/rep_set.h32
-rw-r--r--src/theory/rewriterules/rr_inst_match.cpp23
-rw-r--r--src/theory/rewriterules/rr_inst_match.h2
-rw-r--r--src/theory/rewriterules/rr_trigger.cpp20
-rw-r--r--src/theory/rewriterules/rr_trigger.h3
-rw-r--r--src/theory/rewriterules/theory_rewriterules.h2
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.cpp15
-rw-r--r--src/theory/rewriterules/theory_rewriterules_type_rules.h2
-rw-r--r--src/theory/shared_terms_database.cpp4
-rw-r--r--src/theory/strings/Makefile4
-rw-r--r--src/theory/strings/Makefile.am19
-rw-r--r--src/theory/strings/kinds105
-rw-r--r--src/theory/strings/options11
-rw-r--r--src/theory/strings/theory_strings.cpp1711
-rw-r--r--src/theory/strings/theory_strings.h244
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp135
-rw-r--r--src/theory/strings/theory_strings_preprocess.h44
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp156
-rw-r--r--src/theory/strings/theory_strings_rewriter.h49
-rw-r--r--src/theory/strings/theory_strings_type_rules.h223
-rw-r--r--src/theory/strings/type_enumerator.h130
-rw-r--r--src/theory/substitutions.cpp75
-rw-r--r--src/theory/substitutions.h20
-rw-r--r--src/theory/term_registration_visitor.cpp9
-rw-r--r--src/theory/term_registration_visitor.h15
-rw-r--r--src/theory/theory.cpp28
-rw-r--r--src/theory/theory.h37
-rw-r--r--src/theory/theory_engine.cpp349
-rw-r--r--src/theory/theory_engine.h40
-rw-r--r--src/theory/theory_test_utils.h5
-rw-r--r--src/theory/theoryof_mode.h16
-rw-r--r--src/theory/type_enumerator.h21
-rw-r--r--src/theory/uf/equality_engine.cpp2
-rw-r--r--src/theory/uf/equality_engine.h14
-rw-r--r--src/theory/uf/options12
-rw-r--r--src/theory/uf/symmetry_breaker.cpp37
-rw-r--r--src/theory/uf/symmetry_breaker.h28
-rw-r--r--src/theory/uf/theory_uf.cpp3
-rw-r--r--src/theory/uf/theory_uf_model.cpp96
-rw-r--r--src/theory/uf/theory_uf_model.h16
-rw-r--r--src/theory/uf/theory_uf_rewriter.h1
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp265
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h45
-rw-r--r--src/util/Makefile.am13
-rw-r--r--src/util/bitvector.h14
-rw-r--r--src/util/boolean_simplification.h2
-rw-r--r--src/util/chain.h50
-rw-r--r--src/util/chain.i12
-rw-r--r--src/util/cvc4_assert.cpp2
-rw-r--r--src/util/cvc4_assert.h14
-rw-r--r--src/util/datatype.h1
-rw-r--r--src/util/debug.h4
-rw-r--r--src/util/divisible.cpp29
-rw-r--r--src/util/divisible.h62
-rw-r--r--src/util/divisible.i10
-rw-r--r--src/util/dump.h1
-rw-r--r--src/util/exception.h8
-rw-r--r--src/util/ite_removal.cpp6
-rw-r--r--src/util/output.h2
-rw-r--r--src/util/output.i70
-rw-r--r--src/util/rational_cln_imp.h4
-rw-r--r--src/util/record.h1
-rw-r--r--src/util/recursion_breaker.h2
-rw-r--r--src/util/regexp.h353
-rw-r--r--src/util/result.cpp21
-rw-r--r--src/util/result.h33
-rw-r--r--src/util/result.i3
-rw-r--r--src/util/sort_inference.cpp308
-rw-r--r--src/util/sort_inference.h46
-rw-r--r--src/util/statistics_registry.h2
-rw-r--r--src/util/util_model.cpp2
-rw-r--r--src/util/util_model.h12
-rw-r--r--test/Makefile.am3
-rw-r--r--test/regress/regress0/Makefile.am34
-rw-r--r--test/regress/regress0/arith/Makefile.am11
-rw-r--r--test/regress/regress0/arith/div.09.smt25
-rw-r--r--test/regress/regress0/arith/integers/Makefile.am20
-rw-r--r--test/regress/regress0/arith/mult.02.smt24
-rw-r--r--test/regress/regress0/arrays/Makefile.am6
-rw-r--r--test/regress/regress0/aufbv/Makefile.am7
-rw-r--r--test/regress/regress0/aufbv/bug509.smt117
-rw-r--r--test/regress/regress0/auflia/Makefile.am7
-rw-r--r--test/regress/regress0/bug512.minimized.smt28
-rw-r--r--test/regress/regress0/bug512.smt2147
-rw-r--r--test/regress/regress0/bug516.smt216
-rw-r--r--test/regress/regress0/bug519.smt276
-rw-r--r--test/regress/regress0/bug520.smt2173
-rw-r--r--test/regress/regress0/bug521.minimized.smt215
-rw-r--r--test/regress/regress0/bug521.smt2323
-rw-r--r--test/regress/regress0/bug522.smt215
-rw-r--r--test/regress/regress0/bv/Makefile.am6
-rw-r--r--test/regress/regress0/bv/core/Makefile.am6
-rw-r--r--test/regress/regress0/chained-equality.smt210
-rw-r--r--test/regress/regress0/datatypes/Makefile.am8
-rw-r--r--test/regress/regress0/datatypes/empty_tuprec.cvc20
-rw-r--r--test/regress/regress0/decision/Makefile.am19
-rw-r--r--test/regress/regress0/decision/bug374a.smt1197
-rw-r--r--test/regress/regress0/decision/bug374a.smt.expect (renamed from test/regress/regress0/decision/pp-regfile.smt.expect)0
-rw-r--r--test/regress/regress0/decision/bug374b.smt214
-rw-r--r--test/regress/regress0/decision/bug374b.smt2.expect3
-rw-r--r--test/regress/regress0/fmf/ALG008-1.smt273
-rw-r--r--test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt265
-rw-r--r--test/regress/regress0/fmf/Hoare-z3.931718.smt50
-rw-r--r--test/regress/regress0/fmf/Makefile.am52
-rw-r--r--test/regress/regress0/fmf/PUZ001+1.smt2119
-rw-r--r--test/regress/regress0/fmf/QEpres-uf.855035.smt85
-rw-r--r--test/regress/regress0/fmf/agree466.smt2475
-rw-r--r--test/regress/regress0/fmf/agree467.smt2342
-rwxr-xr-xtest/regress/regress0/fmf/bug0909.smt255
-rw-r--r--test/regress/regress0/fmf/german169.smt2104
-rw-r--r--test/regress/regress0/fmf/german73.smt2106
-rw-r--r--test/regress/regress0/fmf/refcount24.cvc.smt238
-rw-r--r--test/regress/regress0/lemmas/Makefile.am6
-rw-r--r--test/regress/regress0/precedence/Makefile.am6
-rw-r--r--test/regress/regress0/preprocess/Makefile.am6
-rw-r--r--test/regress/regress0/push-pop/Makefile.am9
-rw-r--r--test/regress/regress0/push-pop/arith/Makefile.am6
-rw-r--r--test/regress/regress0/push-pop/boolean/Makefile.am6
-rw-r--r--test/regress/regress0/quantifiers/Makefile.am11
-rw-r--r--test/regress/regress0/rewriterules/Makefile.am6
-rw-r--r--test/regress/regress0/strings/Makefile8
-rw-r--r--test/regress/regress0/strings/Makefile.am52
-rw-r--r--test/regress/regress0/strings/cardinality.smt223
-rw-r--r--test/regress/regress0/strings/loop001.smt213
-rw-r--r--test/regress/regress0/strings/loop002.smt210
-rw-r--r--test/regress/regress0/strings/loop003.smt213
-rw-r--r--test/regress/regress0/strings/loop004.smt213
-rw-r--r--test/regress/regress0/strings/loop005.smt220
-rw-r--r--test/regress/regress0/strings/loop006.smt215
-rw-r--r--test/regress/regress0/strings/loop007.smt210
-rw-r--r--test/regress/regress0/strings/model001.smt212
-rw-r--r--test/regress/regress0/strings/str001.smt216
-rw-r--r--test/regress/regress0/strings/str002.smt218
-rw-r--r--test/regress/regress0/strings/str003.smt215
-rw-r--r--test/regress/regress0/strings/str004.smt215
-rw-r--r--test/regress/regress0/strings/str005.smt218
-rw-r--r--test/regress/regress0/tptp/ARI086=1.p32
-rw-r--r--test/regress/regress0/tptp/Axioms/BOO004-0.ax48
-rw-r--r--test/regress/regress0/tptp/Axioms/SYN000+0.ax37
-rw-r--r--test/regress/regress0/tptp/Axioms/SYN000-0.ax34
-rw-r--r--test/regress/regress0/tptp/Axioms/SYN000_0.ax47
-rw-r--r--test/regress/regress0/tptp/BOO003-4.p31
-rw-r--r--test/regress/regress0/tptp/BOO027-1.p48
-rw-r--r--test/regress/regress0/tptp/DAT001=1.p57
-rw-r--r--test/regress/regress0/tptp/KRS018+1.p55
-rw-r--r--test/regress/regress0/tptp/KRS063+1.p181
-rw-r--r--test/regress/regress0/tptp/MGT019+2.p84
-rw-r--r--test/regress/regress0/tptp/MGT031-1.p95
-rw-r--r--test/regress/regress0/tptp/MGT041-2.p61
-rw-r--r--test/regress/regress0/tptp/Makefile8
-rw-r--r--test/regress/regress0/tptp/Makefile.am83
-rw-r--r--test/regress/regress0/tptp/NLP114-1.p202
-rw-r--r--test/regress/regress0/tptp/PUZ131_1.p100
-rw-r--r--test/regress/regress0/tptp/SYN000+1.p99
-rw-r--r--test/regress/regress0/tptp/SYN000+2.p127
-rw-r--r--test/regress/regress0/tptp/SYN000-1.p83
-rw-r--r--test/regress/regress0/tptp/SYN000-2.p117
-rw-r--r--test/regress/regress0/tptp/SYN000=2.p309
-rw-r--r--test/regress/regress0/tptp/SYN000_1.p170
-rw-r--r--test/regress/regress0/tptp/SYN000_2.p135
-rw-r--r--test/regress/regress0/tptp/SYN075+1.p46
-rw-r--r--test/regress/regress0/tptp/SYN075-1.p76
-rw-r--r--test/regress/regress0/tptp/tff0-arith.p27
-rw-r--r--test/regress/regress0/tptp/tff0.p37
-rw-r--r--test/regress/regress0/tptp/tptp_parser.p (renamed from test/regress/regress0/tptp_parser.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser10.p (renamed from test/regress/regress0/tptp_parser10.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser2.p (renamed from test/regress/regress0/tptp_parser2.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser3.p (renamed from test/regress/regress0/tptp_parser3.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser4.p (renamed from test/regress/regress0/tptp_parser4.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser5.p (renamed from test/regress/regress0/tptp_parser5.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser6.p (renamed from test/regress/regress0/tptp_parser6.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser7.p (renamed from test/regress/regress0/tptp_parser7.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser8.p (renamed from test/regress/regress0/tptp_parser8.p)3
-rw-r--r--test/regress/regress0/tptp/tptp_parser9.p (renamed from test/regress/regress0/tptp_parser9.p)3
-rw-r--r--test/regress/regress0/uf/Makefile.am6
-rw-r--r--test/regress/regress0/uflia/Makefile.am10
-rw-r--r--test/regress/regress0/uflra/Makefile.am9
-rw-r--r--test/regress/regress0/unconstrained/Makefile.am6
-rw-r--r--test/regress/regress1/DTP_k2_n35_c175_s15.smt2 (renamed from test/regress/regress0/arith/DTP_k2_n35_c175_s15.smt2)0
-rw-r--r--test/regress/regress1/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2 (renamed from test/regress/regress0/uflia/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2)0
-rw-r--r--test/regress/regress1/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect (renamed from test/regress/regress0/uflia/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect)0
-rw-r--r--test/regress/regress1/GEO123+1.minimized.smt2397
-rw-r--r--test/regress/regress1/Makefile.am24
-rw-r--r--test/regress/regress1/arith/Makefile.am6
-rw-r--r--test/regress/regress1/auflia-fuzz06.smt (renamed from test/regress/regress0/auflia/fuzz06.smt)0
-rw-r--r--test/regress/regress1/bug394.smt2 (renamed from test/regress/regress0/push-pop/bug394.smt2)0
-rw-r--r--test/regress/regress1/error0.smt2 (renamed from test/regress/regress0/uflia/error0.smt2)0
-rw-r--r--test/regress/regress1/error1.smt (renamed from test/regress/regress0/uflra/error1.smt)0
-rw-r--r--test/regress/regress1/piVC_5581bd.smt2 (renamed from test/regress/regress0/quantifiers/piVC_5581bd.smt2)0
-rw-r--r--test/regress/regress1/typed_v1l50016-simp.cvc (renamed from test/regress/regress0/datatypes/typed_v1l50016-simp.cvc)0
-rw-r--r--test/regress/regress1/uflia-error0.smt2 (renamed from test/regress/regress0/decision/uflia-error0.smt2)0
-rw-r--r--test/regress/regress1/uflia-error0.smt2.expect (renamed from test/regress/regress0/decision/uflia-error0.smt2.expect)0
-rw-r--r--test/regress/regress1/xs-09-16-3-4-1-5.decn.smt (renamed from test/regress/regress0/uflia/xs-09-16-3-4-1-5.smt)0
-rw-r--r--test/regress/regress1/xs-09-16-3-4-1-5.decn.smt.expect3
-rw-r--r--test/regress/regress1/xs-09-16-3-4-1-5.smt29
-rw-r--r--test/regress/regress2/Makefile.am17
-rw-r--r--test/regress/regress2/bug497.cvc (renamed from test/regress/regress0/bug497.cvc)0
-rw-r--r--test/regress/regress2/incorrect1.smt (renamed from test/regress/regress0/uflra/incorrect1.smt)0
-rw-r--r--test/regress/regress2/incorrect2.smt (renamed from test/regress/regress0/uflra/incorrect2.smt)0
-rw-r--r--test/regress/regress2/pp-regfile.smt (renamed from test/regress/regress0/decision/pp-regfile.smt)0
-rw-r--r--test/regress/regress2/pp-regfile.smt.expect3
-rw-r--r--test/regress/regress3/Makefile.am6
-rwxr-xr-xtest/regress/run_regression37
-rw-r--r--test/system/Makefile.am7
-rw-r--r--test/unit/expr/attribute_white.h12
-rw-r--r--test/unit/expr/expr_public.h2
-rw-r--r--test/unit/expr/type_cardinality_public.h2
-rw-r--r--test/unit/parser/parser_black.h2
-rw-r--r--test/unit/theory/logic_info_white.h17
-rw-r--r--test/unit/theory/theory_arith_white.h36
-rw-r--r--test/unit/theory/theory_engine_white.h3
-rw-r--r--test/unit/theory/theory_white.h5
485 files changed, 24255 insertions, 8244 deletions
diff --git a/.project b/.project
index 252288336..b1fd9f133 100644
--- a/.project
+++ b/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>cvc4-bvprop</name>
+ <name>cvc4-idl</name>
<comment></comment>
<projects>
</projects>
diff --git a/INSTALL b/INSTALL
index 57620bd72..cbf8c8a86 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-CVC4 release version 1.1.
+CVC4 release version 1.2.
*** Quick-start instructions
diff --git a/Makefile b/Makefile
index 468371197..923d6afe6 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@ all install examples install-examples .DEFAULT:
cd $(builddir); \
echo $(MAKE) $@; \
$(MAKE) $@ || exit 1; \
+ $(MAKE) show-config; \
else \
echo; \
echo 'Run configure first, or type "make" in a configured build directory.'; \
diff --git a/Makefile.am b/Makefile.am
index 9e9f73a3b..41586cbe7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,6 +33,15 @@ LCOV_EXCLUDES = \
"/usr/include/*" \
"$(abs_top_builddir)/test/*"
+.PHONY: show-config
+show-config:
+ @echo
+ @echo '==============================================================================='
+ @echo 'This CVC4 build was configured with:'
+ @echo ' configure $(cvc4_config_cmdline)'
+ @echo '==============================================================================='
+ @echo
+
.PHONY: lcov lcov-all lcov18
if COVERAGE_ENABLED
diff --git a/NEWS b/NEWS
index 8c93b1478..8ce85b817 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,33 @@
This file contains a summary of important user-visible changes.
+Changes since 1.2
+=================
+
+* SMT-LIB support for abs, to_real, to_int, is_int
+* Expr::substitute() now capable of substituting operators (e.g.,
+ function symbols under an APPLY_UF)
+* Support in linear logics for /, div, and mod by constants.
+* Support for TPTP's TFF and TFA formats.
+* We no longer permit model or proof generation if there's been an
+ intervening push/pop.
+* Increased compliance to SMT-LIBv2, numerous bugs and usability issues
+ resolved.
+* New :command-verbosity SMT option to silence success and error messages
+ on a per-command basis. API changes to Command infrastructure to support.
+* A new theory of strings. Currently, only word equations are supported.
+
Changes since 1.1
=================
-* nothing notable yet
+* Real arithmetic now has three simplex solvers for exact precision linear
+ arithmetic: the classical dual solver and two new solvers based on
+ techniques for minimizing the sum of infeasibilities. GLPK can now be used
+ as a heuristic backup to the exact precision solvers. GLPK must be enabled
+ at configure time. See --help for more information on enabling these solvers.
+* added support for "bit0" and "bit1" bitvector constants in SMT-LIB v1.2
+* support for theory "alternates": new ability to prototype new decision
+ procedures that are selectable at runtime
+* various bugfixes
Changes since 1.0
=================
diff --git a/README b/README
index bda916610..ddb8c856e 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is CVC4 release version 1.1. For build and installation notes,
+This is CVC4 release version 1.2. For build and installation notes,
please see the INSTALL file included with this distribution.
This first official release of CVC4 is the result of more than three
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 43d87487a..136051d0b 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -1,4 +1,4 @@
-Release Notes for CVC4 1.1, April 2013
+Release Notes for CVC4 1.2, May 2013
** Getting started
@@ -17,7 +17,7 @@ this, you can use the --lang option.
The CVC family of systems relies on Type Correctness Conditions (TCCs) when
mixing two types that have a compatible base type. TCCs, and the checking of
-such, are not supported by CVC4 1.1. This is an issue when mixing integers and
+such, are not supported by CVC4 1.2. This is an issue when mixing integers and
reals. A function defined only on integers can be applied to REAL (as INT is a
subtype of REAL), and CVC4 will not complain. It is up to the user to ensure
that the REAL expression must be an integer. If the REAL expression is not
@@ -36,8 +36,8 @@ For example:
This kind of problem can be identified by checking TCCs. Though CVC4 does not
(yet) support TCCs, CVC3 can be used to produce TCCs for this input (with the
-+dump-tcc option). The TCC can be checked by CVC3 or another solver. (CVC3 can
-also check TCCs while solving with +tcc.)
++dump-tcc option). The TCC can then be checked by CVC4 or another solver.
+(CVC3 can also check TCCs at the same time it creates them, with +tcc.)
** Changes in CVC's Presentation Language
@@ -69,8 +69,8 @@ QUERY commands.
CVC4 supports rational literals (of type REAL) in decimal; CVC3 did not
support decimals.
-CVC4 does not have support for the IS_INTEGER predicate, or for predicate
-subtypes, although these are planned for future releases.
+CVC4 does not have support for predicate subtypes, although these are
+planned for future releases.
** SMT-LIB compliance
@@ -118,7 +118,7 @@ heap.
** Proof support
-CVC4 1.1 has limited support for proofs, and they are disabled by default.
+CVC4 1.2 has limited support for proofs, and they are disabled by default.
(Run the configure script with --enable-proof to enable proofs). Proofs
are exported in LFSC format and are limited to the propositional backbone
of the discovered proof (theory lemmas are stated without proof in this
@@ -126,7 +126,7 @@ release).
** Nonlinear arithmetic
-CVC4 1.1 has a state-of-the-art linear arithmetic solver. However, there
+CVC4 1.2 has a state-of-the-art linear arithmetic solver. However, there
is extremely limited support for nonlinear arithmetic in this release.
** Portfolio solving
diff --git a/THANKS b/THANKS
index b135fe36e..f6586d2dc 100644
--- a/THANKS
+++ b/THANKS
@@ -1,3 +1,6 @@
Thanks to Peter Collingbourne and his group (the Multicore Programming Group
at Imperial College London) for developing and submitting some patches in
September 2012 related to SMT-LIBv2 compliance.
+
+Thanks to David Cok of GrammaTech, Inc., for suggesting numerous improvements
+in CVC4's SMT-LIBv2 compliance in May 2013.
diff --git a/config/bindings.m4 b/config/bindings.m4
index 6aa9b1ac5..3f75479bd 100644
--- a/config/bindings.m4
+++ b/config/bindings.m4
@@ -10,6 +10,17 @@ AC_DEFUN([CVC4_SUPPORTED_BINDINGS],
AC_DEFUN([CVC4_ALL_BINDINGS],
[c,java,csharp,perl,php,python,ruby,tcl,ocaml])
+# CVC4_NEED_SWIG_FOR_BINDING
+# --------------------------
+# Used by CVC4_CHECK_BINDINGS to ensure swig is available (and correct
+# version) when a binding needs it
+AC_DEFUN([CVC4_NEED_SWIG_FOR_BINDING], [
+ if test -z "$SWIG"; then
+ AC_MSG_WARN([swig not available or incompatible version; $binding bindings require swig 2.0.0 or later])
+ binding_error=yes
+ fi
+])
+
# CVC4_CHECK_BINDINGS(DEFAULT_BINDINGS_LIST)
# ------------------------------------------
# Check for user language binding preferences, and what is possible
@@ -41,7 +52,27 @@ else
AC_CHECK_PROG(SWIG, "$SWIG", "$SWIG", [])
fi
if test -z "$SWIG"; then
+ AC_MSG_RESULT([not found])
AC_MSG_WARN([language bindings for native API disabled, swig not found.])
+ else
+ AC_MSG_CHECKING([compatibility with version of swig])
+ cat > conftest.c << _CVC4EOF
+%module conftest
+#if !defined(SWIG_VERSION) || SWIG_VERSION < 0x020000
+#error bad version
+#endif
+_CVC4EOF
+ if $SWIG conftest.c >&AS_MESSAGE_LOG_FD 2>&1; then
+ AC_MSG_RESULT([compatible version])
+ else
+ AC_MSG_RESULT([incompatible version])
+ AC_MSG_WARN([swig version 2.0.0 or later is required to build native API bindings])
+ SWIG=
+ echo '===Failed swig input was:' >&AS_MESSAGE_LOG_FD
+ cat conftest.c >&AS_MESSAGE_LOG_FD
+ echo '===End failed swig input' >&AS_MESSAGE_LOG_FD
+ rm -f conftest.c
+ fi
fi
fi
@@ -78,30 +109,35 @@ for binding in $try_bindings; do
AC_MSG_RESULT([C support will be built]);;
java)
AC_MSG_RESULT([Java support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(JAVA_CPPFLAGS, [flags to pass to compiler when building Java bindings])
CPPFLAGS="$CPPFLAGS $JAVA_CPPFLAGS"
AC_CHECK_HEADER([jni.h], [cvc4_build_java_bindings=yes], [binding_error=yes])
;;
csharp)
AC_MSG_RESULT([[C# support will be built]])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(CSHARP_CPPFLAGS, [flags to pass to compiler when building C# bindings])
CPPFLAGS="$CPPFLAGS $CSHARP_CPPFLAGS"
cvc4_build_csharp_bindings=yes
;;
perl)
AC_MSG_RESULT([perl support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(PERL_CPPFLAGS, [flags to pass to compiler when building perl bindings])
CPPFLAGS="$CPPFLAGS $PERL_CPPFLAGS"
AC_CHECK_HEADER([EXTERN.h], [cvc4_build_perl_bindings=yes], [binding_error=yes])
;;
php)
AC_MSG_RESULT([php support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(PHP_CPPFLAGS, [flags to pass to compiler when building PHP bindings])
CPPFLAGS="$CPPFLAGS $PHP_CPPFLAGS"
AC_CHECK_HEADER([zend.h], [cvc4_build_php_bindings=yes], [binding_error=yes])
;;
python)
AC_MSG_RESULT([python support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AM_PATH_PYTHON([2.5], [cvc4_build_python_bindings=yes], [binding_error=yes])
AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for python, bypassing python-config])
AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])
@@ -122,18 +158,21 @@ for binding in $try_bindings; do
;;
ruby)
AC_MSG_RESULT([ruby support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(RUBY_CPPFLAGS, [flags to pass to compiler when building ruby bindings])
CPPFLAGS="$CPPFLAGS $RUBY_CPPFLAGS"
AC_CHECK_HEADER([ruby.h], [cvc4_build_ruby_bindings=yes], [binding_error=yes])
;;
tcl)
AC_MSG_RESULT([tcl support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(TCL_CPPFLAGS, [flags to pass to compiler when building tcl bindings])
CPPFLAGS="$CPPFLAGS $TCL_CPPFLAGS"
AC_CHECK_HEADER([tcl.h], [cvc4_build_tcl_bindings=yes], [binding_error=yes])
;;
ocaml)
AC_MSG_RESULT([OCaml support will be built])
+ CVC4_NEED_SWIG_FOR_BINDING
AC_ARG_VAR(TCL_CPPFLAGS, [flags to pass to compiler when building OCaml bindings])
CPPFLAGS="$CPPFLAGS $OCAML_CPPFLAGS"
AC_CHECK_HEADER([caml/misc.h], [cvc4_build_ocaml_bindings=yes], [binding_error=yes])
diff --git a/config/cvc4.m4 b/config/cvc4.m4
index 0eca68c13..1b241feb4 100644
--- a/config/cvc4.m4
+++ b/config/cvc4.m4
@@ -13,9 +13,8 @@ dnl _AS_ME_PREPARE
AC_DEFUN([CVC4_REWRITE_ARGS_FOR_BUILD_PROFILE],
[m4_divert_push([PARSE_ARGS])dnl
-unset ac_cvc4_rewritten_args
-for ac_option
-do
+handle_option() {
+ ac_option="$[]1"
case $ac_option in
-*|*=*) ;;
production|production-*|debug|debug-*|default|default-*|competition|competition-*)
@@ -55,6 +54,24 @@ do
ac_option="--with-build=$ac_option_build"
esac
eval 'ac_cvc4_rewritten_args="${ac_cvc4_rewritten_args+$ac_cvc4_rewritten_args }'\'\$ac_option\'\"
+}
+
+unset ac_cvc4_rewritten_args
+for ac_option
+do
+ if test "$ac_option" = personal; then
+ if test -e personal.conf; then
+ handle_option --enable-personal-make-rules
+ while read arg; do
+ handle_option "$arg"
+ done < personal.conf
+ else
+ AC_MSG_ERROR([personal build profile selected, but cannot find personal.conf])
+ fi
+ else
+echo "calling for $ac_option"
+ handle_option "$ac_option"
+ fi
done
eval set x $ac_cvc4_rewritten_args
shift
@@ -102,3 +119,19 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([int main() { return 0; }])],
AC_LANG_POP([C++])
CXXFLAGS="$cvc4_save_CXXFLAGS"
])# CVC4_CXX_OPTION
+
+# CVC4_C_OPTION(OPTION, VAR)
+# --------------------------
+# Run $(CC) $(CPPFLAGS) $(CFLAGS) OPTION and see if the compiler
+# likes it. If so, add OPTION to shellvar VAR.
+AC_DEFUN([CVC4_C_OPTION], [
+AC_MSG_CHECKING([whether $CC supports $1])
+cvc4_save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $C_WERROR $1"
+AC_LANG_PUSH([C])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([int main() { return 0; }])],
+ [AC_MSG_RESULT([yes]); $2='$1'],
+ [AC_MSG_RESULT([no])])
+AC_LANG_POP([C])
+CFLAGS="$cvc4_save_CFLAGS"
+])# CVC4_C_OPTION
diff --git a/config/doxygen.cfg b/config/doxygen.cfg
index f4713b616..f385fb94a 100644
--- a/config/doxygen.cfg
+++ b/config/doxygen.cfg
@@ -1247,7 +1247,7 @@ SEARCH_INCLUDES = YES
# contain include files that are not input files but should be processed by
# the preprocessor.
-INCLUDE_PATH = . include $(SRCDIR)/src $(SRCDIR)/src/include
+INCLUDE_PATH = . $(SRCDIR)/src $(SRCDIR)/src/include
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
diff --git a/config/glpk.m4 b/config/glpk.m4
index 7380ad0e2..6c59a3094 100644
--- a/config/glpk.m4
+++ b/config/glpk.m4
@@ -13,8 +13,10 @@ elif test "$with_glpk" = yes; then
dnl Try a bunch of combinations until something works :-/
GLPK_LIBS=
- AC_CHECK_HEADER([glpk.h], [],
- [AC_MSG_FAILURE([cannot find glpk.h, the GLPK header!])])
+ AC_CHECK_HEADERS([glpk/glpk.h glpk.h], [break])
+ if test x$ac_cv_header_glpk_glpk_h = xno && test x$ac_cv_header_glpk_h = xno; then
+ AC_MSG_FAILURE([cannot find glpk.h, the GLPK header!])
+ fi
AC_MSG_CHECKING([how to link glpk])
CVC4_TRY_GLPK_WITH([])
CVC4_TRY_GLPK_WITH([-lgmp])
@@ -88,7 +90,11 @@ if test -z "$GLPK_LIBS"; then
AC_LANG_PUSH([C++])
cvc4_save_LIBS="$LIBS"
LIBS="-lglpk $1"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <glpk.h>],
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#ifdef HAVE_GLPK_GLPK_H]
+ [#include <glpk/glpk.h>]
+ [#else]
+ [#include <glpk.h>]
+ [#endif],
[int i = lpx_get_int_parm(NULL, LPX_K_ITCNT)])],
[GLPK_LIBS="-lglpk $1"],
[])
@@ -107,7 +113,11 @@ if test -z "$GLPK_LIBS"; then
cvc4_save_LDFLAGS="$LDFLAGS"
LDFLAGS="-static $LDFLAGS"
LIBS="-lglpk $1"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <glpk.h>],
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#ifdef HAVE_GLPK_GLPK_H]
+ [#include <glpk/glpk.h>]
+ [#else]
+ [#include <glpk.h>]
+ [#endif],
[int i = lpx_get_int_parm(NULL, LPX_K_ITCNT)])],
[GLPK_LIBS="-lglpk $1"],
[])
diff --git a/configure.ac b/configure.ac
index e860461b9..56f462b34 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
m4_define(_CVC4_MAJOR, 1) dnl version (major)
-m4_define(_CVC4_MINOR, 2) dnl version (minor)
+m4_define(_CVC4_MINOR, 3) dnl version (minor)
m4_define(_CVC4_RELEASE, 0) dnl version (alpha)
m4_define(_CVC4_EXTRAVERSION, [-prerelease]) dnl version (extra)
m4_define(_CVC4_RELEASE_STRING, _CVC4_MAJOR[.]_CVC4_MINOR[]m4_if(_CVC4_RELEASE,[0],,[.]_CVC4_RELEASE)_CVC4_EXTRAVERSION) dnl version string
@@ -69,6 +69,7 @@ CVC4_BINDINGS_LIBRARY_VERSION=_CVC4_BINDINGS_LIBRARY_VERSION
# included in the output... autoconf overrides us on the orderings of
# some things.)
config_cmdline=("$@")
+cvc4_config_cmdline="${config_cmdline[[@]]}"
# remember if the user set these explicitly (or whether autoconf does)
user_specified_enable_or_disable_static=${enable_static+yes}
@@ -106,7 +107,7 @@ fi
AC_MSG_CHECKING([for requested build profile])
AC_ARG_WITH([build],
[AS_HELP_STRING([--with-build=profile],
- [for profile in {production,debug,default,competition}])])
+ [for profile in {production,debug,default,competition,personal}])])
if test -z "${with_build+set}" -o "$with_build" = default; then
with_build=default
@@ -786,6 +787,9 @@ AC_DEFINE_UNQUOTED(CVC4_GCC_HAS_PB_DS_BUG, ${CVC4_GCC_HAS_PB_DS_BUG}, [Whether l
AC_PROG_ANTLR
CVC4_CXX_OPTION([-Werror], [WERROR])
+CVC4_C_OPTION([-Werror], [C_WERROR])
+CVC4_CXX_OPTION([-Wno-deprecated], [WNO_DEPRECATED])
+CVC4_C_OPTION([-Wno-deprecated], [C_WNO_DEPRECATED])
CVC4_CXX_OPTION([-Wno-conversion-null], [WNO_CONVERSION_NULL])
CVC4_CXX_OPTION([-Wno-tautological-compare], [WNO_TAUTOLOGICAL_COMPARE])
CVC4_CXX_OPTION([-Wno-parentheses], [WNO_PARENTHESES])
@@ -809,6 +813,21 @@ if test "$target_vendor" = apple; then
CVC4CPPFLAGS="${CVC4CPPFLAGS:+$CVC4CPPFLAGS }-D_GLIBCXX_VISIBILITY_DEFAULT=\"__attribute__((__visibility__(\\\"default\\\")))\""
fi
+# Tell top-level Makefile to include $(top_srcdir)/personal.mk
+AC_ARG_ENABLE([personal-make-rules],
+ [AS_HELP_STRING([--enable-personal-make-rules],
+ [include top-level personal.mk (if it exists)])])
+if test "$enable_personal_make_rules" = yes; then
+ # This allows us to include a personal.mk makefile from every
+ # generated makefile. Named zz_* in order to make sure this
+ # comes last, so it gets other definitions (in particular top_srcdir).
+ zz_cvc4_use_personal_make_rules='yes
+
+include $(top_srcdir)/personal.mk
+$(top_srcdir)/personal.mk:; @touch "$@"'
+ AC_SUBST([zz_cvc4_use_personal_make_rules])
+fi
+
# Doxygen configuration
AC_ARG_ENABLE([internals-documentation],
[AS_HELP_STRING([--enable-internals-documentation],
@@ -976,6 +995,11 @@ AC_CHECK_HEADERS([getopt.h unistd.h])
#AC_TYPE_UINT64_T
#AC_TYPE_SIZE_T
+# guard against double-inclusion of the autoheader
+AH_TOP([#ifndef __CVC4__CVC4AUTOCONFIG_H
+#define __CVC4__CVC4AUTOCONFIG_H])
+AH_BOTTOM([#endif /* __CVC4__CVC4AUTOCONFIG_H */])
+
AC_CHECK_DECLS([optreset], [], [], [#include <getopt.h>])
# check with which standard strerror_r() complies
@@ -1032,8 +1056,8 @@ cvc4_rlcheck_save_CXXFLAGS="$CXXFLAGS"
cvc4_rlcheck_save_CFLAGS="$CFLAGS"
cvc4_rlcheck_save_LDFLAGS="$LDFLAGS"
CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }${BOOST_CPPFLAGS:+$BOOST_CPPFLAGS }$CVC4CPPFLAGS"
-CXXFLAGS="${CXXFLAGS:+$CXXFLAGS }$CVC4CXXFLAGS -Wno-deprecated"
-CFLAGS="${CFLAGS:+$CFLAGS }$CVC4CFLAGS -Wno-deprecated -fexceptions"
+CXXFLAGS="${CXXFLAGS:+$CXXFLAGS }$CVC4CXXFLAGS $WNO_DEPRECATED"
+CFLAGS="${CFLAGS:+$CFLAGS }$CVC4CFLAGS $C_WNO_DEPRECATED -fexceptions"
LDFLAGS="${LDFLAGS:+$LDFLAGS }$CVC4LDFLAGS"
CVC4_CHECK_FOR_READLINE
CPPFLAGS="$cvc4_rlcheck_save_CPPFLAGS"
@@ -1188,6 +1212,9 @@ AC_SUBST(FLAG_VISIBILITY_HIDDEN)
AC_SUBST(cvc4_LDFLAGS)
AC_SUBST(pcvc4_LDFLAGS)
+# remember the command line used for configure
+AC_SUBST(cvc4_config_cmdline)
+
# mk_include
#
# When automake scans Makefiles, it complains about non-standard make
@@ -1203,6 +1230,11 @@ AC_SUBST(pcvc4_LDFLAGS)
# makefiles with GNU extensions; this hides them from automake.
mk_include=include
AC_SUBST(mk_include)
+# Similar trickery for "if"
+mk_if=if
+AC_SUBST(mk_if)
+mk_empty=
+AC_SUBST(mk_empty)
# CVC4_FALSE
#
diff --git a/contrib/get-antlr-3.4 b/contrib/get-antlr-3.4
index 49b0b54a7..7a8f64f69 100755
--- a/contrib/get-antlr-3.4
+++ b/contrib/get-antlr-3.4
@@ -25,8 +25,9 @@ function webget {
fi
}
-if [[ -z "${MACHINE_TYPE}" ]]; then
- MACHINE_TYPE=`uname -m`
+if [ -z "${MACHINE_TYPE}" ]; then
+ # get first nibble from config.guess (x86_64, i686, ...)
+ MACHINE_TYPE=`config/config.guess | sed 's,-.*,,'`
fi
set -x
@@ -59,12 +60,33 @@ cp Makefile Makefile.orig
sed 's,^\(CFLAGS = .*\),\1 -fexceptions,' Makefile.orig > Makefile
make
make install
+cd ../..
+mv lib/libantlr3c.a lib/libantlr3c-static.a
+
+cd src/libantlr3c-3.4
+make clean
+
+if [ ${MACHINE_TYPE} == 'x86_64' ]; then
+ # 64-bit stuff here
+ ./configure --enable-64bit --with-pic --disable-shared --disable-antlrdebug --prefix=`pwd`/../.. $ANTLR_CONFIGURE_ARGS
+else
+ # 32-bit stuff here
+ ./configure --with-pic --disable-shared --disable-antlrdebug --prefix=`pwd`/../.. $ANTLR_CONFIGURE_ARGS
+fi
+
+cp Makefile Makefile.orig
+sed 's,^\(CFLAGS = .*\),\1 -fexceptions,' Makefile.orig > Makefile
+make
+make install
+cd ../..
+mv lib/libantlr3c.la lib/libantlr3c.la.orig
+awk '/^old_library=/ {print "old_library='\''libantlr3c-static.a'\''"} /^library_names=/ {print "library_names='\''libantlr3c.a'\''"} !/^old_library=/ && !/^library_names=/ {print}' < lib/libantlr3c.la.orig > lib/libantlr3c.la
set +x
-cd ../../..
+cd ..
-echo
-echo Invalidating generated parsers..
-touch src/parser/*/*.g
+# echo
+# echo Invalidating generated parsers..
+# touch src/parser/*/*.g
if [ ${MACHINE_TYPE} == 'x86_64' ]; then
# 64-bit stuff here
diff --git a/contrib/get-bug-attachments b/contrib/get-bug-attachments
index 3bb433c51..869eee895 100755
--- a/contrib/get-bug-attachments
+++ b/contrib/get-bug-attachments
@@ -70,14 +70,14 @@ function webget {
count=0
for attachment in $(\
- webcat "http://church.cims.nyu.edu/bugs/show_bug.cgi?id=$bugid" 2>/dev/null \
+ webcat "http://cvc4.cs.nyu.edu/bugs/show_bug.cgi?id=$bugid" 2>/dev/null \
| grep ' href="attachment.cgi?id=[0-9][0-9]*' \
| sed 's,.* href="attachment.cgi?id=\([0-9][0-9]*\).*,\1,' \
| sort -nu); do
let count++
printf "%-30s " "Downloading attachment $attachment..."
- webget "http://church.cims.nyu.edu/bugs/attachment.cgi?id=$attachment" "test/regress/regress0/bug$bugid"
+ webget "http://cvc4.cs.nyu.edu/bugs/attachment.cgi?id=$attachment" "test/regress/regress0/bug$bugid"
done
diff --git a/contrib/run-script-casc24-fnt b/contrib/run-script-casc24-fnt
new file mode 100755
index 000000000..b10d7324a
--- /dev/null
+++ b/contrib/run-script-casc24-fnt
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+cvc4=./cvc4
+bench="$1"
+let "to = $2 - 60"
+
+file=${bench##*/}
+filename=${file%.*}
+
+# use: trywith [params..]
+# to attempt a run. Only thing printed on stdout is "sat" or "unsat", in
+# which case this run script terminates immediately. Otherwise, this
+# function returns normally.
+function trywith {
+ limit=$1; shift;
+ (ulimit -t "$limit";$cvc4 -L tptp --szs-compliant --no-checking --no-interactive --dump-models --produce-models "$@" $bench) 2>/dev/null |
+ (read result;
+ case "$result" in
+ sat) echo "% SZS status" "Satisfiable for $filename";
+ echo "% SZS output" "start FiniteModel for $filename";
+ cat;
+ echo "% SZS output" "end FiniteModel for $filename";
+ exit 0;;
+ unsat) echo "% SZS status" "Unsatisfiable for $filename"; exit 0;;
+ conjecture-sat) echo "% SZS status" "CounterSatisfiable for $filename";
+ echo "% SZS output" "start FiniteModel for $filename";
+ cat;
+ echo "% SZS output" "end FiniteModel for $filename";
+ exit 0;;
+ conjecture-unsat) echo "% SZS status" "Theorem for $filename"; exit 0;;
+ esac; exit 1)
+ if [ ${PIPESTATUS[1]} -eq 0 ]; then exit 0; fi
+}
+
+trywith 30 --finite-model-find --uf-ss-totality
+trywith 30 --finite-model-find --decision=justification --fmf-fmc
+trywith $to --finite-model-find --decision=justification
+echo "% SZS status" "GaveUp for $filename"
diff --git a/contrib/run-script-casc24-fnt-no-models b/contrib/run-script-casc24-fnt-no-models
new file mode 100755
index 000000000..3b4d5e320
--- /dev/null
+++ b/contrib/run-script-casc24-fnt-no-models
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+cvc4=./cvc4
+bench="$1"
+let "to = $2 - 60"
+
+file=${bench##*/}
+filename=${file%.*}
+
+# use: trywith [params..]
+# to attempt a run. Only thing printed on stdout is "sat" or "unsat", in
+# which case this run script terminates immediately. Otherwise, this
+# function returns normally.
+function trywith {
+ result="$( ulimit -t "$1";shift;$cvc4 -L tptp --szs-compliant --no-checking --no-interactive "$@" $bench)"
+ case "$result" in
+ sat) echo "% SZS status" "Satisfiable for $filename"; exit 0;;
+ unsat) echo "% SZS status" "Unsatisfiable for $filename"; exit 0;;
+ conjecture-sat) echo "% SZS status" "CounterSatisfiable for $filename"; exit 0;;
+ conjecture-unsat) echo "% SZS status" "Theorem for $filename"; exit 0;;
+ esac
+}
+function finishwith {
+ result="$( $cvc4 -L tptp --szs-compliant --no-checking --no-interactive "$@" $bench)"
+ case "$result" in
+ sat) echo "% SZS status" "Satisfiable for $filename"; exit 0;;
+ unsat) echo "% SZS status" "Unsatisfiable for $filename"; exit 0;;
+ conjecture-sat) echo "% SZS status" "CounterSatisfiable for $filename"; exit 0;;
+ conjecture-unsat) echo "% SZS status" "Theorem for $filename"; exit 0;;
+ esac
+}
+
+trywith 30 --finite-model-find --uf-ss-totality
+trywith 30 --finite-model-find --decision=justification --fmf-fmc
+trywith $to --finite-model-find --decision=justification
+echo "% SZS status" "GaveUp for $filename"
diff --git a/contrib/run-script-casc24-fof b/contrib/run-script-casc24-fof
new file mode 100755
index 000000000..b3ede0dfa
--- /dev/null
+++ b/contrib/run-script-casc24-fof
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+cvc4=./cvc4
+bench="$1"
+let "to = $2 - 75"
+
+file=${bench##*/}
+filename=${file%.*}
+
+# use: trywith [params..]
+# to attempt a run. Only thing printed on stdout is "sat" or "unsat", in
+# which case this run script terminates immediately. Otherwise, this
+# function returns normally.
+function trywith {
+ result="$( ulimit -t "$1";shift;$cvc4 -L tptp --szs-compliant --no-checking --no-interactive "$@" $bench)"
+ case "$result" in
+ sat) echo "% SZS status" "Satisfiable for $filename"; exit 0;;
+ unsat) echo "% SZS status" "Unsatisfiable for $filename"; exit 0;;
+ conjecture-sat) echo "% SZS status" "CounterSatisfiable for $filename"; exit 0;;
+ conjecture-unsat) echo "% SZS status" "Theorem for $filename"; exit 0;;
+ esac
+}
+function finishwith {
+ result="$( $cvc4 -L tptp --szs-compliant --no-checking --no-interactive "$@" $bench)"
+ case "$result" in
+ sat) echo "% SZS status" "Satisfiable for $filename"; exit 0;;
+ unsat) echo "% SZS status" "Unsatisfiable for $filename"; exit 0;;
+ conjecture-sat) echo "% SZS status" "CounterSatisfiable for $filename"; exit 0;;
+ conjecture-unsat) echo "% SZS status" "Theorem for $filename"; exit 0;;
+ esac
+}
+
+trywith 30
+trywith 15 --finite-model-find --fmf-inst-engine
+trywith 30 --finite-model-find --decision=justification --fmf-fmc
+trywith $to --decision=justification
+echo "% SZS status" "GaveUp for $filename"
diff --git a/contrib/run-script-smteval2013 b/contrib/run-script-smteval2013
index 3c71b28e7..2212f71c7 100755
--- a/contrib/run-script-smteval2013
+++ b/contrib/run-script-smteval2013
@@ -1,16 +1,16 @@
#!/bin/bash
-cat >bench-$$.smt2
-trap 'rm bench-$$.smt2' EXIT
+cvc4=./cvc4
+bench="$1"
-logic=$(expr "$(head -n 1 bench-$$.smt2)" : ' *(set-logic *\([A-Z_]*\) *) *$')
+logic=$(expr "$(grep -m1 '^[^;]*set-logic' "$bench")" : ' *(set-logic *\([A-Z_]*\) *) *$')
# use: trywith [params..]
# to attempt a run. Only thing printed on stdout is "sat" or "unsat", in
# which case this run script terminates immediately. Otherwise, this
# function returns normally.
function trywith {
- result="$(./cvc4 -L smt2 --no-checking --no-interactive "$@" bench-$$.smt2)"
+ result="$($cvc4 --stats -L smt2 --no-checking --no-interactive "$@" $bench)"
case "$result" in
sat|unsat) echo "$result"; exit 0;;
esac
@@ -19,29 +19,35 @@ function trywith {
# use: finishwith [params..]
# to run cvc4 and let it output whatever it will to stdout.
function finishwith {
- ./cvc4 -L smt2 --no-checking --no-interactive "$@" bench-$$.smt2
+ $cvc4 --stats -L smt2 --no-checking --no-interactive "$@" $bench
}
case "$logic" in
QF_LRA)
- # 3 minutes with default decision heuristic
- trywith --tlimit-per=180000
- # switch to internal decision heuristic
- finishwith --decision=internal
+ finishwith --no-restrict-pivots --enable-miplib-trick --miplib-trick-subs=2 --fc-penalties --collect-pivot-stats --use-soi --new-prop --dio-decomps --unconstrained-simp --fancy-final
;;
-AUFLIA)
+AUFLIA|AUFLIRA|AUFNIRA|UFLRA|UFNIA)
# 60 seconds with default decision heuristic
- trywith --tlimit-per=60000
+ trywith --simplification=none --tlimit-per=60000
# try simplification for 60 seconds, default decision heuristic
- trywith --simplification=batch --tlimit-per=60000
+ trywith --tlimit-per=60000
# switch to internal decision heuristic
- finishwith --decision=internal
+ finishwith --simplification=none --decision=internal
+ ;;
+LRA)
+ finishwith --enable-cbqi
;;
QF_AUFBV)
trywith --tlimit-per=600000
finishwith --decision=justification-stoponly
;;
+QF_BV)
+ trywith --bv-core --decision=justification --tlimit-per=10000
+ trywith --decision=justification --tlimit-per=60000
+ trywith --decision=internal --bitblast-eager --tlimit-per=600000
+ finishwith --decision=justification --decision-use-weight --decision-weight-internal=usr1
+ ;;
QF_AX)
trywith --tlimit-per=2000
finishwith --no-arrays-model-based
diff --git a/contrib/theoryskel/README.WHATS-NEXT b/contrib/theoryskel/README.WHATS-NEXT
index ede8054ed..31ff2d47a 100644
--- a/contrib/theoryskel/README.WHATS-NEXT
+++ b/contrib/theoryskel/README.WHATS-NEXT
@@ -3,10 +3,15 @@ Congratulations, you now have a new theory of $dir !
Your next steps will likely be:
* to specify theory constants, types, and operators in your \`kinds' file
-* to add typing rules to theory_${dir}_type_rules.h for your operators
+* to add typing rules to theory_$dir_type_rules.h for your operators
and constants
-* to write code in theory_${dir}_rewriter.h to implement a normal form
+* to write code in theory_$dir_rewriter.h to implement a normal form
for your theory's terms
+* for any new types that you have introduced, add "mk*Type()" functions to
+ the NodeManager and ExprManager in src/expr/node_manager.{h,cpp} and
+ src/expr/expr_manager_template.{h,cpp}. You may also want "is*()" testers
+ in src/expr/type_node.h and a corresponding Type derived class in
+ src/expr/type.h.
* to write parser rules in src/parser/cvc/Cvc.g to support the CVC input
language, src/parser/smt/Smt.g to support the (deprecated) SMT-LIBv1
language, and src/parser/smt2/Smt2.g to support SMT-LIBv2
diff --git a/doc/SmtEngine.3cvc_template.in b/doc/SmtEngine.3cvc_template.in
index 835bef585..3a876fefc 100644
--- a/doc/SmtEngine.3cvc_template.in
+++ b/doc/SmtEngine.3cvc_template.in
@@ -34,7 +34,7 @@ This manual page refers to
version @VERSION@.
.SH BUGS
A Bugzilla for the CVC4 project is maintained at
-.BR http://church.cims.nyu.edu/bugzilla3/ .
+.BR http://cvc4.cs.nyu.edu/bugzilla3/ .
.SH AUTHORS
.B CVC4
is developed by a team of researchers at New York University
@@ -48,4 +48,4 @@ contributors.
Additionally, the CVC4 wiki contains useful information about the
design and internals of CVC4. It is maintained at
-.BR http://church.cims.nyu.edu/wiki/ .
+.BR http://cvc4.cs.nyu.edu/wiki/ .
diff --git a/doc/cvc4.1_template.in b/doc/cvc4.1_template.in
index 5a5f90214..baae1dc4b 100644
--- a/doc/cvc4.1_template.in
+++ b/doc/cvc4.1_template.in
@@ -115,7 +115,7 @@ This manual page refers to
version @VERSION@.
.SH BUGS
A Bugzilla for the CVC4 project is maintained at
-.BR http://church.cims.nyu.edu/bugzilla3/ .
+.BR http://cvc4.cs.nyu.edu/bugzilla3/ .
.SH AUTHORS
.B CVC4
is developed by a team of researchers at New York University
@@ -129,4 +129,4 @@ contributors.
Additionally, the CVC4 wiki contains useful information about the
design and internals of CVC4. It is maintained at
-.BR http://church.cims.nyu.edu/wiki/ .
+.BR http://cvc4.cs.nyu.edu/wiki/ .
diff --git a/doc/cvc4.5.in b/doc/cvc4.5.in
index ab4e8806c..b54f23560 100644
--- a/doc/cvc4.5.in
+++ b/doc/cvc4.5.in
@@ -18,4 +18,4 @@ to background theories of interest.
Additionally, the CVC4 wiki contains useful information about the
design and internals of CVC4. It is maintained at
-.BR http://church.cims.nyu.edu/wiki/ .
+.BR http://cvc4.cs.nyu.edu/wiki/ .
diff --git a/doc/libcvc4compat.3.in b/doc/libcvc4compat.3.in
index 3722557b0..3aa58b712 100644
--- a/doc/libcvc4compat.3.in
+++ b/doc/libcvc4compat.3.in
@@ -12,4 +12,4 @@ libcvc4compat \- a CVC3 compatibility library interface for the CVC4 theorem pro
Additionally, the CVC4 wiki contains useful information about the
design and internals of CVC4. It is maintained at
-.BR http://church.cims.nyu.edu/wiki/ .
+.BR http://cvc4.cs.nyu.edu/wiki/ .
diff --git a/doc/libcvc4parser.3.in b/doc/libcvc4parser.3.in
index 67ec74326..09fea23f1 100644
--- a/doc/libcvc4parser.3.in
+++ b/doc/libcvc4parser.3.in
@@ -12,4 +12,4 @@ libcvc4parser \- a parser library interface for the CVC4 theorem prover
Additionally, the CVC4 wiki contains useful information about the
design and internals of CVC4. It is maintained at
-.BR http://church.cims.nyu.edu/wiki/ .
+.BR http://cvc4.cs.nyu.edu/wiki/ .
diff --git a/doc/options.3cvc_template.in b/doc/options.3cvc_template.in
index 86f2ff976..a0d6c1640 100644
--- a/doc/options.3cvc_template.in
+++ b/doc/options.3cvc_template.in
@@ -22,7 +22,7 @@ This manual page refers to
version @VERSION@.
.SH BUGS
A Bugzilla for the CVC4 project is maintained at
-.BR http://church.cims.nyu.edu/bugzilla3/ .
+.BR http://cvc4.cs.nyu.edu/bugzilla3/ .
.SH AUTHORS
.B CVC4
is developed by a team of researchers at New York University
@@ -36,4 +36,4 @@ contributors.
Additionally, the CVC4 wiki contains useful information about the
design and internals of CVC4. It is maintained at
-.BR http://church.cims.nyu.edu/wiki/ .
+.BR http://cvc4.cs.nyu.edu/wiki/ .
diff --git a/examples/api/java/CVC4Streams.java b/examples/api/java/CVC4Streams.java
new file mode 100644
index 000000000..0b0984bf3
--- /dev/null
+++ b/examples/api/java/CVC4Streams.java
@@ -0,0 +1,59 @@
+/********************* */
+/*! \file CVC4Streams.java
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Example of driving CVC4 parsing from Java streams
+ **
+ ** This example shows how CVC4 can be driven from Java streams.
+ **/
+
+import java.io.*;
+import edu.nyu.acsys.CVC4.*;
+
+public class CVC4Streams {
+ public static void main(String[] args) throws IOException {
+ System.loadLibrary("cvc4jni");
+ ExprManager exprMgr = new ExprManager();
+ SmtEngine smt = new SmtEngine(exprMgr);
+ smt.setOption("incremental", new SExpr(true));
+ smt.setOption("output-language", new SExpr("smt2"));
+
+ PipedOutputStream solverPipe = new PipedOutputStream();
+ PrintWriter toSolver = new PrintWriter(solverPipe);
+ PipedInputStream stream = new PipedInputStream(solverPipe);
+
+ toSolver.println("(set-logic QF_LIA)");
+ toSolver.println("(declare-fun x () Int)");
+ toSolver.println("(assert (= x 5))");
+ toSolver.println("(check-sat)");
+ toSolver.flush();
+
+ ParserBuilder pbuilder =
+ new ParserBuilder(exprMgr, "<string 1>")
+ .withInputLanguage(InputLanguage.INPUT_LANG_SMTLIB_V2)
+ .withLineBufferedStreamInput((java.io.InputStream)stream);
+ Parser parser = pbuilder.build();
+
+ Command cmd;
+ while((cmd = parser.nextCommand()) != null) {
+ System.out.println(cmd);
+ cmd.invoke(smt, System.out);
+ }
+
+ toSolver.println("(assert (= x 10))");
+ toSolver.println("(check-sat)");
+ toSolver.flush();
+
+ while((cmd = parser.nextCommand()) != null) {
+ System.out.println(cmd);
+ cmd.invoke(smt, System.out);
+ }
+ }
+}
diff --git a/examples/api/java/Makefile.am b/examples/api/java/Makefile.am
index 84c818737..f4b8f1043 100644
--- a/examples/api/java/Makefile.am
+++ b/examples/api/java/Makefile.am
@@ -2,6 +2,7 @@ noinst_DATA =
if CVC4_LANGUAGE_BINDING_JAVA
noinst_DATA += \
+ CVC4Streams.class \
BitVectors.class \
BitVectorsAndArrays.class \
Combination.class \
@@ -14,6 +15,7 @@ endif
$(AM_V_JAVAC)$(JAVAC) -classpath "@builddir@/../../../src/bindings/CVC4.jar" -d "@builddir@" $<
EXTRA_DIST = \
+ CVC4Streams.java \
BitVectors.java \
BitVectorsAndArrays.java \
Combination.java \
diff --git a/library_versions b/library_versions
index 1cf417e36..ad37ce67a 100644
--- a/library_versions
+++ b/library_versions
@@ -50,3 +50,8 @@
1\.1 libcvc4:1:0:0 libcvc4parser:1:0:0 libcvc4compat:1:0:0 libcvc4bindings:1:0:0
1\.1\.1-prerelease libcvc4:1:0:0 libcvc4parser:1:0:0 libcvc4compat:1:0:0 libcvc4bindings:1:0:0
1\.2-prerelease libcvc4:1:0:0 libcvc4parser:1:0:0 libcvc4compat:1:0:0 libcvc4bindings:1:0:0
+1\.2 libcvc4:1:1:1 libcvc4parser:1:1:0 libcvc4compat:1:0:0 libcvc4bindings:1:0:0
+1\.2\.1-prerelease libcvc4:1:1:1 libcvc4parser:1:1:0 libcvc4compat:1:0:0 libcvc4bindings:1:0:0
+1\.3-prerelease libcvc4:1:1:1 libcvc4parser:1:1:0 libcvc4compat:1:0:0 libcvc4bindings:1:0:0
+# note: SmtEngine::setLogicString() exceptions have changed, bump library version on next release?
+# note: removed Parser::getDeclarationLevel(), added other interfaces
diff --git a/src/Makefile.am b/src/Makefile.am
index 64d95deed..e6d5f80ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -110,7 +110,7 @@ svn_versioninfo.cpp: svninfo
# This .tmp business is to keep from having to re-compile options.cpp
# (and then re-link the libraries) if nothing has changed.
svninfo: svninfo.tmp
- $(AM_V_GEN)diff -q svninfo.tmp svninfo &>/dev/null || mv svninfo.tmp svninfo || true
+ $(AM_V_GEN)if diff -q svninfo.tmp svninfo &>/dev/null; then rm -f svninfo.tmp; else mv svninfo.tmp svninfo; fi
# .PHONY ensures the .tmp version is always rebuilt (to check for any changes)
.PHONY: svninfo.tmp
svninfo.tmp:
@@ -138,7 +138,7 @@ git_versioninfo.cpp: gitinfo
# This .tmp business is to keep from having to re-compile options.cpp
# (and then re-link the libraries) if nothing has changed.
gitinfo: gitinfo.tmp
- $(AM_V_GEN)diff -q gitinfo.tmp gitinfo &>/dev/null || mv gitinfo.tmp gitinfo || true
+ $(AM_V_GEN)if diff -q gitinfo.tmp gitinfo &>/dev/null; then rm -f gitinfo.tmp; else mv gitinfo.tmp gitinfo; fi || true
# .PHONY ensures the .tmp version is always rebuilt (to check for any changes)
.PHONY: gitinfo.tmp
gitinfo.tmp:
@@ -163,15 +163,18 @@ install-data-local:
$(mkinstalldirs) "$$(dirname "$(DESTDIR)$(includedir)/cvc4/$$d")"; \
if [ -e "$$f" ]; then \
path="$$f"; \
- fixpath="$$f.fix"; \
else \
path="$(srcdir)/$$f"; \
- fixpath="$(builddir)/$$f.fix"; \
- $(MKDIR_P) "`dirname "$$fixpath"`"; \
fi; \
+ fixpath="$(top_builddir)/header_install.fix"; \
sed 's,^\([ \t]*#[ \t]*include[ \t*]\)"\(.*\)"\([ \t]*\)$$,\1<cvc4/\2>\3,' "$$path" > "$$fixpath" || exit 1; \
echo $(INSTALL_DATA) "$$fixpath" "$(DESTDIR)$(includedir)/cvc4/$$d"; \
- $(INSTALL_DATA) "$$fixpath" "$(DESTDIR)$(includedir)/cvc4/$$d" || exit 1; \
+ if $(INSTALL_DATA) "$$fixpath" "$(DESTDIR)$(includedir)/cvc4/$$d"; then \
+ rm -f "$$fixpath"; \
+ else \
+ rm -f "$$fixpath"; \
+ exit 1; \
+ fi; \
done
uninstall-local:
@@ -196,34 +199,3 @@ uninstall-local:
-rmdir "$(DESTDIR)$(includedir)/cvc4/bindings"
-rmdir "$(DESTDIR)$(includedir)/cvc4"
-rmdir "$(DESTDIR)$(libdir)/ocaml/cvc4"
-
-# clean up the .fix files
-mostlyclean-local:
- (echo include/cvc4.h; \
- echo include/cvc4_public.h; \
- echo include/cvc4parser_public.h; \
- echo util/tls.h; \
- echo util/integer.h; \
- echo util/rational.h; \
- find * -name '*.h.fix' | \
- xargs grep -l '^# *include *<cvc4/cvc4.*_public\.h>' | \
- sed 's,\.fix$$,,'; \
- (cd "$(srcdir)" && find * -name '*.h' | \
- xargs grep -l '^# *include *"cvc4.*_public\.h"')) | \
- while read f; do \
- if expr "$$f" : ".*_\(template\|private\|private_library\|test_utils\)\.h$$" &>/dev/null; then \
- continue; \
- fi; \
- d="$$(echo "$$f" | sed 's,^include/,,')"; \
- if [ -e "$$f" ]; then \
- path="$$f"; \
- fixpath="$$f.fix"; \
- else \
- path="$(srcdir)/$$f"; \
- fixpath="$(builddir)/$$f.fix"; \
- $(MKDIR_P) "`dirname "$$fixpath"`"; \
- fi; \
- echo rm -f "$$fixpath"; \
- rm -f "$$fixpath"; \
- done
-
diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am
index cc2a7c53f..80e65d180 100644
--- a/src/bindings/Makefile.am
+++ b/src/bindings/Makefile.am
@@ -142,7 +142,7 @@ endif
endif
nodist_java_libcvc4jni_la_SOURCES = java.cpp
-java_libcvc4jni_la_CXXFLAGS = @FNO_STRICT_ALIASING@ @WNO_UNUSED_VARIABLE@ @WNO_UNINITIALIZED@
+java_libcvc4jni_la_CXXFLAGS = -Wno-all @FNO_STRICT_ALIASING@ @WNO_UNUSED_VARIABLE@ @WNO_UNINITIALIZED@
nodist_csharp_CVC4_la_SOURCES = csharp.cpp
nodist_perl_CVC4_la_SOURCES = perl.cpp
nodist_php_CVC4_la_SOURCES = php.cpp
@@ -171,7 +171,9 @@ MOSTLYCLEANFILES = \
$(patsubst %,%.d,$(filter-out c c++,$(CVC4_LANGUAGE_BINDINGS))) \
CVC4.jar
-java_libcvc4jni_la-java.lo java.lo: java.cpp
+java_libcvc4jni_la-java.lo: java.cpp
+ $(AM_V_CXX)$(LTCXXCOMPILE) -c $(JAVA_CPPFLAGS) $(java_libcvc4jni_la_CXXFLAGS) -o $@ $<
+java.lo: java.cpp
$(AM_V_CXX)$(LTCXXCOMPILE) -c $(JAVA_CPPFLAGS) $(java_libcvc4jni_la_CXXFLAGS) -o $@ $<
CVC4.jar: java.cpp
$(AM_V_GEN) \
diff --git a/src/bindings/compat/java/include/cvc3/JniUtils.h b/src/bindings/compat/java/include/cvc3/JniUtils.h
index 567c691fe..404774c62 100644
--- a/src/bindings/compat/java/include/cvc3/JniUtils.h
+++ b/src/bindings/compat/java/include/cvc3/JniUtils.h
@@ -109,7 +109,7 @@ namespace Java_cvc3_JniUtils {
// embeds a c++ object into a jobject,
// and takes over the responsibility to deallocate it
template <class T> jobject embed_own(JNIEnv* env, T* cobj) {
- DebugAssert(&cobj != NULL, "JniUtils::embed_own: null object given");
+ DebugAssert(cobj != NULL, "JniUtils::embed_own: null object given");
return embed<T>(env, cobj, typeid(cobj), &DeleteEmbedded<T>::deleteEmbedded);
}
diff --git a/src/compat/cvc3_compat.cpp b/src/compat/cvc3_compat.cpp
index 0ecc6b5c7..2b552684a 100644
--- a/src/compat/cvc3_compat.cpp
+++ b/src/compat/cvc3_compat.cpp
@@ -25,6 +25,7 @@
#include "util/hash.h"
#include "util/subrange_bound.h"
#include "util/predicate.h"
+#include "util/output.h"
#include "parser/parser.h"
#include "parser/parser_builder.h"
@@ -1065,8 +1066,8 @@ Type ValidityChecker::intType() {
}
Type ValidityChecker::subrangeType(const Expr& l, const Expr& r) {
- bool noLowerBound = l.getType().isString() && l.getConst<string>() == "_NEGINF";
- bool noUpperBound = r.getType().isString() && r.getConst<string>() == "_POSINF";
+ bool noLowerBound = l.getType().isString() && l.getConst<CVC4::String>() == "_NEGINF";
+ bool noUpperBound = r.getType().isString() && r.getConst<CVC4::String>() == "_POSINF";
CVC4::CheckArgument(noLowerBound || (l.getKind() == CVC4::kind::CONST_RATIONAL && l.getConst<Rational>().isIntegral()), l);
CVC4::CheckArgument(noUpperBound || (r.getKind() == CVC4::kind::CONST_RATIONAL && r.getConst<Rational>().isIntegral()), r);
CVC4::SubrangeBound bl = noLowerBound ? CVC4::SubrangeBound() : CVC4::SubrangeBound(l.getConst<Rational>().getNumerator());
@@ -1196,7 +1197,7 @@ void ValidityChecker::dataType(const std::vector<std::string>& names,
CVC4::CheckArgument(selectors[i][j].size() == types[i][j].size(), types, "expected sub-vectors in selectors and types vectors to match in size");
for(unsigned k = 0; k < selectors[i][j].size(); ++k) {
if(types[i][j][k].getType().isString()) {
- ctor.addArg(selectors[i][j][k], CVC4::DatatypeUnresolvedType(types[i][j][k].getConst<string>()));
+ ctor.addArg(selectors[i][j][k], CVC4::DatatypeUnresolvedType(types[i][j][k].getConst<CVC4::String>().toString()));
} else {
ctor.addArg(selectors[i][j][k], exprToType(types[i][j][k]));
}
@@ -1306,12 +1307,12 @@ Expr ValidityChecker::getTypePred(const Type&t, const Expr& e) {
}
Expr ValidityChecker::stringExpr(const std::string& str) {
- return d_em->mkConst(str);
+ return d_em->mkConst(CVC4::String(str));
}
Expr ValidityChecker::idExpr(const std::string& name) {
// represent as a string expr, CVC4 doesn't have id exprs
- return d_em->mkConst(name);
+ return d_em->mkConst(CVC4::String(name));
}
Expr ValidityChecker::listExpr(const std::vector<Expr>& kids) {
@@ -1332,21 +1333,21 @@ Expr ValidityChecker::listExpr(const Expr& e1, const Expr& e2, const Expr& e3) {
Expr ValidityChecker::listExpr(const std::string& op,
const std::vector<Expr>& kids) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), vector<CVC4::Expr>(kids.begin(), kids.end()));
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), vector<CVC4::Expr>(kids.begin(), kids.end()));
}
Expr ValidityChecker::listExpr(const std::string& op, const Expr& e1) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), e1);
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), e1);
}
Expr ValidityChecker::listExpr(const std::string& op, const Expr& e1,
const Expr& e2) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), e1, e2);
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), e1, e2);
}
Expr ValidityChecker::listExpr(const std::string& op, const Expr& e1,
const Expr& e2, const Expr& e3) {
- return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(op), e1, e2, e3);
+ return d_em->mkExpr(CVC4::kind::SEXPR, d_em->mkConst(CVC4::String(op)), e1, e2, e3);
}
void ValidityChecker::printExpr(const Expr& e) {
@@ -2273,7 +2274,7 @@ void ValidityChecker::popto(int stackLevel) {
}
int ValidityChecker::scopeLevel() {
- return d_parserContext->getDeclarationLevel();
+ return d_parserContext->scopeLevel();
}
void ValidityChecker::pushScope() {
@@ -2287,12 +2288,12 @@ void ValidityChecker::popScope() {
void ValidityChecker::poptoScope(int scopeLevel) {
CVC4::CheckArgument(scopeLevel >= 0, scopeLevel,
"Cannot pop to a negative scope level %d", scopeLevel);
- CVC4::CheckArgument(unsigned(scopeLevel) <= d_parserContext->getDeclarationLevel(),
+ CVC4::CheckArgument(unsigned(scopeLevel) <= d_parserContext->scopeLevel(),
scopeLevel,
"Cannot pop to a scope level higher than the current one! "
"At scope level %u, user requested scope level %d",
- d_parserContext->getDeclarationLevel(), scopeLevel);
- while(unsigned(scopeLevel) < d_parserContext->getDeclarationLevel()) {
+ d_parserContext->scopeLevel(), scopeLevel);
+ while(unsigned(scopeLevel) < d_parserContext->scopeLevel()) {
popScope();
}
}
diff --git a/src/cvc4.i b/src/cvc4.i
index 965452b84..6e9380146 100644
--- a/src/cvc4.i
+++ b/src/cvc4.i
@@ -54,9 +54,11 @@ using namespace CVC4;
#include "expr/expr.h"
#include "util/datatype.h"
#include "expr/command.h"
-#include "bindings/java_stream_adapters.h"
+#ifdef SWIGJAVA
+#include "bindings/java_stream_adapters.h"
std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
+#endif
%}
%template(vectorCommandPtr) std::vector< CVC4::Command* >;
@@ -248,7 +250,6 @@ std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
%include "util/bool.i"
%include "util/sexpr.i"
%include "util/statistics.i"
-%include "util/output.i"
%include "util/result.i"
%include "util/configuration.i"
%include "util/bitvector.i"
diff --git a/src/decision/Makefile.am b/src/decision/Makefile.am
index 6d49c6301..f75a17a69 100644
--- a/src/decision/Makefile.am
+++ b/src/decision/Makefile.am
@@ -12,9 +12,7 @@ libdecision_la_SOURCES = \
decision_engine.cpp \
decision_strategy.h \
justification_heuristic.h \
- justification_heuristic.cpp \
- relevancy.h \
- relevancy.cpp
+ justification_heuristic.cpp
EXTRA_DIST = \
options_handlers.h
diff --git a/src/decision/decision_engine.cpp b/src/decision/decision_engine.cpp
index 687515ff0..073a3ff6b 100644
--- a/src/decision/decision_engine.cpp
+++ b/src/decision/decision_engine.cpp
@@ -16,7 +16,6 @@
#include "decision/decision_engine.h"
#include "decision/justification_heuristic.h"
-#include "decision/relevancy.h"
#include "expr/node.h"
#include "decision/options.h"
@@ -62,18 +61,6 @@ void DecisionEngine::init()
enableStrategy(ds);
d_needIteSkolemMap.push_back(ds);
}
- if(options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY) {
- if(options::incrementalSolving()) {
- Warning() << "Relevancy decision heuristic and incremental not supported together"
- << std::endl;
- return; // Currently not supported with incremental
- }
- RelevancyStrategy* ds =
- new decision::Relevancy(this, d_satContext);
- enableStrategy(ds);
- d_needIteSkolemMap.push_back(ds);
- d_relevancyStrategy = ds;
- }
}
@@ -82,6 +69,13 @@ void DecisionEngine::enableStrategy(DecisionStrategy* ds)
d_enabledStrategies.push_back(ds);
}
+void DecisionEngine::clearStrategies(){
+ for(unsigned i = 0; i < d_enabledStrategies.size(); ++i){
+ delete d_enabledStrategies[i];
+ }
+ d_enabledStrategies.clear();
+ d_needIteSkolemMap.clear();
+}
bool DecisionEngine::isRelevant(SatVariable var)
{
@@ -105,13 +99,6 @@ SatValue DecisionEngine::getPolarity(SatVariable var)
}
}
-
-
-
-
-
-
-
void DecisionEngine::addAssertions(const vector<Node> &assertions)
{
Assert(false); // doing this so that we revisit what to do
@@ -139,15 +126,4 @@ void DecisionEngine::addAssertions(const vector<Node> &assertions,
addAssertions(assertions, assertionsEnd, iteSkolemMap);
}
-// void DecisionEngine::addAssertion(Node n)
-// {
-// d_result = SAT_VALUE_UNKNOWN;
-// if(needIteSkolemMap()) {
-// d_assertions.push_back(n);
-// }
-// for(unsigned i = 0; i < d_needIteSkolemMap.size(); ++i)
-// d_needIteSkolemMap[i]->notifyAssertionsAvailable();
-// }
-
-
}/* CVC4 namespace */
diff --git a/src/decision/decision_engine.h b/src/decision/decision_engine.h
index bc071f7f6..f28b13774 100644
--- a/src/decision/decision_engine.h
+++ b/src/decision/decision_engine.h
@@ -96,6 +96,10 @@ public:
/* enables decision stragies based on options */
void init();
+ /* clears all of the strategies */
+ void clearStrategies();
+
+
/**
* This is called by SmtEngine, at shutdown time, just before
* destruction. It is important because there are destruction
@@ -106,8 +110,7 @@ public:
d_engineState = 2;
Trace("decision") << "Shutting down decision engine" << std::endl;
- for(unsigned i = 0; i < d_enabledStrategies.size(); ++i)
- delete d_enabledStrategies[i];
+ clearStrategies();
}
// Interface for External World to use our services
diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp
index de49f6e0a..78de1a74e 100644
--- a/src/decision/justification_heuristic.cpp
+++ b/src/decision/justification_heuristic.cpp
@@ -96,7 +96,8 @@ CVC4::prop::SatLiteral JustificationHeuristic::getNextThresh(bool &stopSearch, D
Debug("decision") << "---" << std::endl << d_assertions[i] << std::endl;
// Sanity check: if it was false, aren't we inconsistent?
- Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE);
+ // Commenting out. See bug 374. In short, to do with how CNF stream works.
+ // Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE);
SatValue desiredVal = SAT_VALUE_TRUE;
SatLiteral litDecision;
@@ -105,6 +106,7 @@ CVC4::prop::SatLiteral JustificationHeuristic::getNextThresh(bool &stopSearch, D
if(litDecision != undefSatLiteral) {
setPrvsIndex(i);
+ Trace("decision") << "jh: spliting on " << litDecision << std::endl;
return litDecision;
}
}
@@ -441,8 +443,9 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
Assert(desiredVal != SAT_VALUE_UNKNOWN, "expected known value");
/* Good luck, hope you can get what you want */
- Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN,
- "invariant violated");
+ // See bug 374
+ // Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN,
+ // "invariant violated");
/* What type of node is this */
Kind k = node.getKind();
@@ -458,12 +461,12 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
* If not in theory of booleans, check if this is something to split-on.
*/
if(tId != theory::THEORY_BOOL) {
-
// if node has embedded ites, resolve that first
if(handleEmbeddedITEs(node) == FOUND_SPLITTER)
return FOUND_SPLITTER;
if(litVal != SAT_VALUE_UNKNOWN) {
+ Assert(litVal == desiredVal);
setJustified(node);
return NO_SPLITTER;
}
diff --git a/src/decision/options b/src/decision/options
index b86577e7b..1f0b137cb 100644
--- a/src/decision/options
+++ b/src/decision/options
@@ -6,17 +6,9 @@
module DECISION "decision/options.h" Decision heuristics
# When/whether to use any decision strategies
-option decisionMode --decision=MODE decision::DecisionMode :handler CVC4::decision::stringToDecisionMode :default decision::DECISION_STRATEGY_INTERNAL :read-write :include "decision/decision_mode.h" :handler-include "decision/options_handlers.h"
+option decisionMode decision-mode --decision=MODE decision::DecisionMode :handler CVC4::decision::stringToDecisionMode :default decision::DECISION_STRATEGY_INTERNAL :read-write :include "decision/decision_mode.h" :handler-include "decision/options_handlers.h"
choose decision mode, see --decision=help
-option decisionRelevancyLeaves bool
-# permille = part per thousand
-option decisionMaxRelTimeAsPermille --decision-budget=N "unsigned short" :read-write :predicate less_equal(1000L) :predicate CVC4::decision::checkDecisionBudget :predicate-include "decision/options_handlers.h"
- impose a budget for relevancy heuristic which increases linearly with each decision. N between 0 and 1000. (default: 1000, no budget)
-# if false, do justification stuff using relevancy.h
-option decisionComputeRelevancy bool
-# use the must be relevant
-option decisionMustRelevancy bool
# only use DE to determine when to stop, not to make decisions
option decisionStopOnly bool
diff --git a/src/decision/options_handlers.h b/src/decision/options_handlers.h
index 05d975ef1..44a623970 100644
--- a/src/decision/options_handlers.h
+++ b/src/decision/options_handlers.h
@@ -37,31 +37,8 @@ justification\n\
justification-stoponly\n\
+ Use the justification heuristic only to stop early, not for decisions\n\
";
-/** Under-development options, commenting out from help for the release */
-/*
-\n\
-relevancy\n\
-+ Under development may-relevancy\n\
-\n\
-relevancy-leaves\n\
-+ May-relevancy, but decide only on leaves\n\
-\n\
-Developer modes:\n\
-\n\
-justification-rel\n\
-+ Use the relevancy code to do the justification stuff\n\
-+ (This should do exact same thing as justification)\n\
-\n\
-justification-must\n\
-+ Start deciding on literals close to root instead of those\n\
-+ near leaves (don't expect it to work well) [Unimplemented]\n\
-";*/
inline DecisionMode stringToDecisionMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
- options::decisionRelevancyLeaves.set(false);
- options::decisionMaxRelTimeAsPermille.set(1000);
- options::decisionComputeRelevancy.set(true);
- options::decisionMustRelevancy.set(false);
options::decisionStopOnly.set(false);
if(optarg == "internal") {
@@ -71,25 +48,6 @@ inline DecisionMode stringToDecisionMode(std::string option, std::string optarg,
} else if(optarg == "justification-stoponly") {
options::decisionStopOnly.set(true);
return DECISION_STRATEGY_JUSTIFICATION;
- } else if(optarg == "relevancy") {
- options::decisionRelevancyLeaves.set(false);
- return DECISION_STRATEGY_RELEVANCY;
- } else if(optarg == "relevancy-leaves") {
- options::decisionRelevancyLeaves.set(true);
- Trace("options") << "version is " << options::version() << std::endl;
- return DECISION_STRATEGY_RELEVANCY;
- } else if(optarg == "justification-rel") {
- // relevancyLeaves : irrelevant
- // maxRelTimeAsPermille : irrelevant
- options::decisionComputeRelevancy.set(false);
- options::decisionMustRelevancy.set(false);
- return DECISION_STRATEGY_RELEVANCY;
- } else if(optarg == "justification-must") {
- // relevancyLeaves : irrelevant
- // maxRelTimeAsPermille : irrelevant
- options::decisionComputeRelevancy.set(false);
- options::decisionMustRelevancy.set(true);
- return DECISION_STRATEGY_RELEVANCY;
} else if(optarg == "help") {
puts(decisionModeHelp.c_str());
exit(1);
@@ -99,14 +57,6 @@ inline DecisionMode stringToDecisionMode(std::string option, std::string optarg,
}
}
-inline void checkDecisionBudget(std::string option, unsigned short budget, SmtEngine* smt) throw(OptionException) {
- if(budget == 0) {
- Warning() << "Decision budget is 0. Consider using internal decision heuristic and "
- << std::endl << " removing this option." << std::endl;
-
- }
-}
-
inline DecisionWeightInternal stringToDecisionWeightInternal(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "off")
return DECISION_WEIGHT_INTERNAL_OFF;
diff --git a/src/decision/relevancy.cpp b/src/decision/relevancy.cpp
deleted file mode 100644
index f83e238d4..000000000
--- a/src/decision/relevancy.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/********************* */
-/*! \file relevancy.cpp
- ** \verbatim
- ** Original author: Kshitij Bansal
- ** Major contributors: none
- ** Minor contributors (to current version): Dejan Jovanovic, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Justification heuristic for decision making
- **
- ** A ATGP-inspired justification-based decision heuristic. See
- ** [insert reference] for more details. This code is, or not, based
- ** on the CVC3 implementation of the same heuristic -- note below.
- **
- ** It needs access to the simplified but non-clausal formula.
- **/
-/*****************************************************************************/
-
-#include "relevancy.h"
-
-#include "expr/node_manager.h"
-#include "expr/kind.h"
-#include "theory/rewriter.h"
-#include "util/ite_removal.h"
-
-// Relevancy stuff
-
-const double Relevancy::secondsPerDecision = 0.001;
-const double Relevancy::secondsPerExpense = 1e-7;
-const double Relevancy::EPS = 1e-9;
-
-
-void Relevancy::setJustified(TNode n)
-{
- Debug("decision") << " marking [" << n.getId() << "]"<< n << "as justified" << std::endl;
- d_justified.insert(n);
- if(options::decisionComputeRelevancy()) {
- d_relevancy[n] = d_maxRelevancy[n];
- updateRelevancy(n);
- }
-}
-
-bool Relevancy::checkJustified(TNode n)
-{
- return d_justified.find(n) != d_justified.end();
-}
-
-SatValue Relevancy::tryGetSatValue(Node n)
-{
- Debug("decision") << " " << n << " has sat value " << " ";
- if(d_decisionEngine->hasSatLiteral(n) ) {
- Debug("decision") << d_decisionEngine->getSatValue(n) << std::endl;
- return d_decisionEngine->getSatValue(n);
- } else {
- Debug("decision") << "NO SAT LITERAL" << std::endl;
- return SAT_VALUE_UNKNOWN;
- }//end of else
-}
-
-void Relevancy::computeITEs(TNode n, IteList &l)
-{
- Debug("jh-ite") << " computeITEs( " << n << ", &l)\n";
- for(unsigned i=0; i<n.getNumChildren(); ++i) {
- SkolemMap::iterator it2 = d_iteAssertions.find(n[i]);
- if(it2 != d_iteAssertions.end())
- l.push_back(it2->second);
- computeITEs(n[i], l);
- }
-}
-
-const Relevancy::IteList& Relevancy::getITEs(TNode n)
-{
- IteCache::iterator it = d_iteCache.find(n);
- if(it != d_iteCache.end()) {
- return it->second;
- } else {
- // Compute the list of ITEs
- // TODO: optimize by avoiding multiple lookup for d_iteCache[n]
- d_iteCache[n] = vector<TNode>();
- computeITEs(n, d_iteCache[n]);
- return d_iteCache[n];
- }
-}
-
-bool Relevancy::findSplitterRec(TNode node,
- SatValue desiredVal)
-{
- Trace("decision")
- << "findSplitterRec([" << node.getId() << "]" << node << ", "
- << desiredVal << ", .. )" << std::endl;
-
- ++d_expense;
-
- /* Handle NOT as a special case */
- while (node.getKind() == kind::NOT) {
- desiredVal = invertValue(desiredVal);
- node = node[0];
- }
-
- /* Avoid infinite loops */
- if(d_visited.find(node) != d_visited.end()) {
- Debug("decision") << " node repeated. kind was " << node.getKind() << std::endl;
- Assert(false);
- Assert(node.getKind() == kind::ITE);
- return false;
- }
-
- /* Base case */
- if(checkJustified(node)) {
- return false;
- }
-
- /**
- * If we have already explored the subtree for some desiredVal, we
- * skip this and continue exploring the rest
- */
- if(d_polarityCache.find(node) == d_polarityCache.end()) {
- d_polarityCache[node] = desiredVal;
- } else {
- Assert(d_multipleBacktrace || options::decisionComputeRelevancy());
- return true;
- }
-
- d_visited.insert(node);
-
-#if defined CVC4_ASSERTIONS || defined CVC4_TRACING
- // We don't always have a sat literal, so remember that. Will need
- // it for some assertions we make.
- bool litPresent = d_decisionEngine->hasSatLiteral(node);
- if(Trace.isOn("decision")) {
- if(!litPresent) {
- Trace("decision") << "no sat literal for this node" << std::endl;
- }
- }
- //Assert(litPresent); -- fails
-#endif
-
- // Get value of sat literal for the node, if there is one
- SatValue litVal = tryGetSatValue(node);
-
- /* You'd better know what you want */
- Assert(desiredVal != SAT_VALUE_UNKNOWN, "expected known value");
-
- /* Good luck, hope you can get what you want */
- Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN,
- "invariant violated");
-
- /* What type of node is this */
- Kind k = node.getKind();
- theory::TheoryId tId = theory::kindToTheoryId(k);
-
- /* Some debugging stuff */
- Trace("jh-findSplitterRec") << "kind = " << k << std::endl;
- Trace("jh-findSplitterRec") << "theoryId = " << tId << std::endl;
- Trace("jh-findSplitterRec") << "node = " << node << std::endl;
- Trace("jh-findSplitterRec") << "litVal = " << litVal << std::endl;
-
- /**
- * If not in theory of booleans, and not a "boolean" EQUAL (IFF),
- * then check if this is something to split-on.
- */
- if(tId != theory::THEORY_BOOL
- // && !(k == kind::EQUAL && node[0].getType().isBoolean())
- ) {
-
- // if node has embedded ites -- which currently happens iff it got
- // replaced during ite removal -- then try to resolve that first
- const IteList& l = getITEs(node);
- Debug("jh-ite") << " ite size = " << l.size() << std::endl;
- for(unsigned i = 0; i < l.size(); ++i) {
- Assert(l[i].getKind() == kind::ITE, "Expected ITE");
- Debug("jh-ite") << " i = " << i
- << " l[i] = " << l[i] << std::endl;
- if(d_visited.find(node) != d_visited.end() ) continue;
- if(findSplitterRec(l[i], SAT_VALUE_TRUE)) {
- d_visited.erase(node);
- return true;
- }
- }
- Debug("jh-ite") << " ite done " << l.size() << std::endl;
-
- if(litVal != SAT_VALUE_UNKNOWN) {
- d_visited.erase(node);
- setJustified(node);
- return false;
- } else {
- /* if(not d_decisionEngine->hasSatLiteral(node))
- throw GiveUpException(); */
- Assert(d_decisionEngine->hasSatLiteral(node));
- SatVariable v = d_decisionEngine->getSatLiteral(node).getSatVariable();
- *d_curDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE );
- Trace("decision") << "decision " << *d_curDecision << std::endl;
- Trace("decision") << "Found something to split. Glad to be able to serve you." << std::endl;
- d_visited.erase(node);
- return true;
- }
- }
-
- bool ret = false;
- SatValue flipCaseVal = SAT_VALUE_FALSE;
- switch (k) {
-
- case kind::CONST_BOOLEAN:
- Assert(node.getConst<bool>() == false || desiredVal == SAT_VALUE_TRUE);
- Assert(node.getConst<bool>() == true || desiredVal == SAT_VALUE_FALSE);
- break;
-
- case kind::AND:
- if (desiredVal == SAT_VALUE_FALSE) ret = handleOrTrue(node, SAT_VALUE_FALSE);
- else ret = handleOrFalse(node, SAT_VALUE_TRUE);
- break;
-
- case kind::OR:
- if (desiredVal == SAT_VALUE_FALSE) ret = handleOrFalse(node, SAT_VALUE_FALSE);
- else ret = handleOrTrue(node, SAT_VALUE_TRUE);
- break;
-
- case kind::IMPLIES:
- Assert(node.getNumChildren() == 2, "Expected 2 fanins");
- if (desiredVal == SAT_VALUE_FALSE) {
- ret = findSplitterRec(node[0], SAT_VALUE_TRUE);
- if(ret) break;
- ret = findSplitterRec(node[1], SAT_VALUE_FALSE);
- break;
- }
- else {
- if (tryGetSatValue(node[0]) != SAT_VALUE_TRUE) {
- ret = findSplitterRec(node[0], SAT_VALUE_FALSE);
- //if(!ret || !d_multipleBacktrace)
- break;
- }
- if (tryGetSatValue(node[1]) != SAT_VALUE_FALSE) {
- ret = findSplitterRec(node[1], SAT_VALUE_TRUE);
- break;
- }
- Assert(d_multipleBacktrace, "No controlling input found (3)");
- }
- break;
-
- case kind::XOR:
- flipCaseVal = SAT_VALUE_TRUE;
- case kind::IFF: {
- SatValue val = tryGetSatValue(node[0]);
- if (val != SAT_VALUE_UNKNOWN) {
- ret = findSplitterRec(node[0], val);
- if (ret) break;
- if (desiredVal == flipCaseVal) val = invertValue(val);
- ret = findSplitterRec(node[1], val);
- }
- else {
- val = tryGetSatValue(node[1]);
- if (val == SAT_VALUE_UNKNOWN) val = SAT_VALUE_FALSE;
- if (desiredVal == flipCaseVal) val = invertValue(val);
- ret = findSplitterRec(node[0], val);
- if(ret) break;
- Assert(false, "Unable to find controlling input (4)");
- }
- break;
- }
-
- case kind::ITE:
- ret = handleITE(node, desiredVal);
- break;
-
- default:
- Assert(false, "Unexpected Boolean operator");
- break;
- }//end of switch(k)
-
- d_visited.erase(node);
- if(ret == false) {
- Assert(litPresent == false || litVal == desiredVal,
- "Output should be justified");
- setJustified(node);
- }
- return ret;
-
- Unreachable();
-}/* findRecSplit method */
-
-bool Relevancy::handleOrFalse(TNode node, SatValue desiredVal) {
- Debug("jh-findSplitterRec") << " handleOrFalse (" << node << ", "
- << desiredVal << std::endl;
-
- Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_TRUE) or
- (node.getKind() == kind::OR and desiredVal == SAT_VALUE_FALSE) );
-
- int n = node.getNumChildren();
- bool ret = false;
- for(int i = 0; i < n; ++i) {
- if (findSplitterRec(node[i], desiredVal)) {
- if(!options::decisionComputeRelevancy())
- return true;
- else
- ret = true;
- }
- }
- return ret;
-}
-
-bool Relevancy::handleOrTrue(TNode node, SatValue desiredVal) {
- Debug("jh-findSplitterRec") << " handleOrTrue (" << node << ", "
- << desiredVal << std::endl;
-
- Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_FALSE) or
- (node.getKind() == kind::OR and desiredVal == SAT_VALUE_TRUE) );
-
- int n = node.getNumChildren();
- SatValue desiredValInverted = invertValue(desiredVal);
- for(int i = 0; i < n; ++i) {
- if ( tryGetSatValue(node[i]) != desiredValInverted ) {
- // PRE RELEVANCY return findSplitterRec(node[i], desiredVal);
- bool ret = findSplitterRec(node[i], desiredVal);
- if(ret) {
- // Splitter could be found... so can't justify this node
- if(!d_multipleBacktrace)
- return true;
- }
- else {
- // Splitter couldn't be found... should be justified
- return false;
- }
- }
- }
- // Multiple backtrace is on, so must have reached here because
- // everything had splitter
- if(d_multipleBacktrace) return true;
-
- if(Debug.isOn("jh-findSplitterRec")) {
- Debug("jh-findSplitterRec") << " * ** " << std::endl;
- Debug("jh-findSplitterRec") << node.getKind() << " "
- << node << std::endl;
- for(unsigned i = 0; i < node.getNumChildren(); ++i)
- Debug("jh-findSplitterRec") << "child: " << tryGetSatValue(node[i])
- << std::endl;
- Debug("jh-findSplitterRec") << "node: " << tryGetSatValue(node)
- << std::endl;
- }
- Assert(false, "No controlling input found");
- return false;
-}
-
-bool Relevancy::handleITE(TNode node, SatValue desiredVal)
-{
- Debug("jh-findSplitterRec") << " handleITE (" << node << ", "
- << desiredVal << std::endl;
-
- //[0]: if, [1]: then, [2]: else
- SatValue ifVal = tryGetSatValue(node[0]);
- if (ifVal == SAT_VALUE_UNKNOWN) {
-
- // are we better off trying false? if not, try true
- SatValue ifDesiredVal =
- (tryGetSatValue(node[2]) == desiredVal ||
- tryGetSatValue(node[1]) == invertValue(desiredVal))
- ? SAT_VALUE_FALSE : SAT_VALUE_TRUE;
-
- if(findSplitterRec(node[0], ifDesiredVal)) return true;
-
- Assert(false, "No controlling input found (6)");
- } else {
-
- // Try to justify 'if'
- if(findSplitterRec(node[0], ifVal)) return true;
-
- // If that was successful, we need to go into only one of 'then'
- // or 'else'
- int ch = (ifVal == SAT_VALUE_TRUE) ? 1 : 2;
- int chVal = tryGetSatValue(node[ch]);
- if( (chVal == SAT_VALUE_UNKNOWN || chVal == desiredVal) &&
- findSplitterRec(node[ch], desiredVal) ) {
- return true;
- }
- }// else (...ifVal...)
- return false;
-}//handleITE
diff --git a/src/decision/relevancy.h b/src/decision/relevancy.h
deleted file mode 100644
index fd16eb0cc..000000000
--- a/src/decision/relevancy.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/********************* */
-/*! \file relevancy.h
- ** \verbatim
- ** Original author: Kshitij Bansal
- ** Major contributors: none
- ** Minor contributors (to current version): Tim King, Dejan Jovanovic, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Justification heuristic for decision making
- **
- ** A ATGP-inspired justification-based decision heuristic. See
- ** [insert reference] for more details. This code is, or not, based
- ** on the CVC3 implementation of the same heuristic.
- **
- ** It needs access to the simplified but non-clausal formula.
- **
- ** Relevancy
- ** ---------
- **
- ** This class also currently computes the may-relevancy of a node
- **
- ** A node is may-relevant if there is a path from the root of the
- ** formula to the node such that no node on the path is justified. As
- ** contrapositive, a node is not relevant (with the may-notion) if all
- ** path from the root to the node go through a justified node.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__DECISION__RELEVANCY
-#define __CVC4__DECISION__RELEVANCY
-
-#include "decision_engine.h"
-#include "decision_strategy.h"
-#include "decision/options.h"
-
-#include "context/cdhashset.h"
-#include "context/cdhashmap.h"
-#include "expr/node.h"
-#include "prop/sat_solver_types.h"
-
-namespace CVC4 {
-
-namespace decision {
-
-class RelGiveUpException : public Exception {
-public:
- RelGiveUpException() :
- Exception("relevancy: giving up") {
- }
-};/* class GiveUpException */
-
-class Relevancy : public RelevancyStrategy {
- typedef std::vector<TNode> IteList;
- typedef hash_map<TNode,IteList,TNodeHashFunction> IteCache;
- typedef hash_map<TNode,TNode,TNodeHashFunction> SkolemMap;
- typedef hash_map<TNode,SatValue,TNodeHashFunction> PolarityCache;
-
- // being 'justified' is monotonic with respect to decisions
- context::CDHashSet<Node, NodeHashFunction> d_justified;
- context::CDO<unsigned> d_prvsIndex;
-
- IntStat d_helfulness;
- IntStat d_polqueries;
- IntStat d_polhelp;
- IntStat d_giveup;
- IntStat d_expense; /* Total number of nodes considered over
- all calls to the findSplitter function */
- TimerStat d_timestat;
-
- /**
- * A copy of the assertions that need to be justified
- * directly. Doesn't have ones introduced during during ITE-removal.
- */
- std::vector<TNode> d_assertions;
- //TNode is fine since decisionEngine has them too
-
- /** map from ite-rewrite skolem to a boolean-ite assertion */
- SkolemMap d_iteAssertions;
- // 'key' being TNode is fine since if a skolem didn't exist anywhere,
- // we won't look it up. as for 'value', same reason as d_assertions
-
- /** Cache for ITE skolems present in a atomic formula */
- IteCache d_iteCache;
-
- /**
- * This is used to prevent infinite loop when trying to find a
- * splitter. Can happen when exploring assertion corresponding to a
- * term-ITE.
- */
- hash_set<TNode,TNodeHashFunction> d_visited;
-
- /**
- * May-relevancy of a node is an integer. For a node n, it becomes
- * irrelevant when d_maxRelevancy[n] = d_relevancy[n]
- */
- hash_map<TNode,int,TNodeHashFunction> d_maxRelevancy;
- context::CDHashMap<TNode,int,TNodeHashFunction> d_relevancy;
- PolarityCache d_polarityCache;
-
- /** **** * * *** * * OPTIONS *** * * ** * * **** */
-
- /**
- * do we do "multiple-backtrace" to try to justify a node
- */
- bool d_multipleBacktrace;
- //bool d_computeRelevancy; // are we in a mode where we compute relevancy?
-
- static const double secondsPerDecision;
- static const double secondsPerExpense;
- static const double EPS;
-
- /** Maximum time this algorithm should spent as part of whole algorithm */
- double d_maxTimeAsPercentageOfTotalTime;
-
- /** current decision for the recursive call */
- SatLiteral* d_curDecision;
-public:
- Relevancy(CVC4::DecisionEngine* de, context::Context *c):
- RelevancyStrategy(de, c),
- d_justified(c),
- d_prvsIndex(c, 0),
- d_helfulness("decision::rel::preventedDecisions", 0),
- d_polqueries("decision::rel::polarityQueries", 0),
- d_polhelp("decision::rel::polarityHelp", 0),
- d_giveup("decision::rel::giveup", 0),
- d_expense("decision::rel::expense", 0),
- d_timestat("decision::rel::time"),
- d_relevancy(c),
- d_multipleBacktrace(options::decisionComputeRelevancy()),
- // d_computeRelevancy(decOpt.computeRelevancy),
- d_maxTimeAsPercentageOfTotalTime(options::decisionMaxRelTimeAsPermille()*1.0/10.0),
- d_curDecision(NULL)
- {
- Warning() << "There are known bugs in this Relevancy code which we know"
- << "how to fix (but haven't yet)." << std::endl
- << "Please bug kshitij if you wish to use." << std::endl;
-
- StatisticsRegistry::registerStat(&d_helfulness);
- StatisticsRegistry::registerStat(&d_polqueries);
- StatisticsRegistry::registerStat(&d_polhelp);
- StatisticsRegistry::registerStat(&d_giveup);
- StatisticsRegistry::registerStat(&d_expense);
- StatisticsRegistry::registerStat(&d_timestat);
- Trace("decision") << "relevancy enabled with" << std::endl;
- Trace("decision") << " * computeRelevancy: " << (options::decisionComputeRelevancy() ? "on" : "off")
- << std::endl;
- Trace("decision") << " * relevancyLeaves: " << (options::decisionRelevancyLeaves() ? "on" : "off")
- << std::endl;
- Trace("decision") << " * mustRelevancy [unimplemented]: " << (options::decisionMustRelevancy() ? "on" : "off")
- << std::endl;
- }
- ~Relevancy() {
- StatisticsRegistry::unregisterStat(&d_helfulness);
- StatisticsRegistry::unregisterStat(&d_polqueries);
- StatisticsRegistry::unregisterStat(&d_polhelp);
- StatisticsRegistry::unregisterStat(&d_giveup);
- StatisticsRegistry::unregisterStat(&d_expense);
- StatisticsRegistry::unregisterStat(&d_timestat);
- }
- prop::SatLiteral getNext(bool &stopSearch) {
- Debug("decision") << std::endl;
- Trace("decision") << "Relevancy::getNext()" << std::endl;
- TimerStat::CodeTimer codeTimer(d_timestat);
-
- if( d_maxTimeAsPercentageOfTotalTime < 100.0 - EPS &&
- double(d_polqueries.getData())*secondsPerDecision <
- d_maxTimeAsPercentageOfTotalTime*double(d_expense.getData())*secondsPerExpense
- ) {
- ++d_giveup;
- return undefSatLiteral;
- }
-
- d_visited.clear();
- d_polarityCache.clear();
-
- for(unsigned i = d_prvsIndex; i < d_assertions.size(); ++i) {
- Trace("decision") << d_assertions[i] << std::endl;
-
- // Sanity check: if it was false, aren't we inconsistent?
- Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE);
-
- SatValue desiredVal = SAT_VALUE_TRUE;
- SatLiteral litDecision = findSplitter(d_assertions[i], desiredVal);
-
- if(!options::decisionComputeRelevancy() && litDecision != undefSatLiteral) {
- d_prvsIndex = i;
- return litDecision;
- }
- }
-
- if(options::decisionComputeRelevancy()) return undefSatLiteral;
-
- Trace("decision") << "jh: Nothing to split on " << std::endl;
-
-#if defined CVC4_ASSERTIONS || defined CVC4_DEBUG
- bool alljustified = true;
- for(unsigned i = 0 ; i < d_assertions.size() && alljustified ; ++i) {
- TNode curass = d_assertions[i];
- while(curass.getKind() == kind::NOT)
- curass = curass[0];
- alljustified &= checkJustified(curass);
-
- if(Debug.isOn("decision")) {
- if(!checkJustified(curass))
- Debug("decision") << "****** Not justified [i="<<i<<"]: "
- << d_assertions[i] << std::endl;
- }
- }
- Assert(alljustified);
-#endif
-
- // SAT solver can stop...
- stopSearch = true;
- d_decisionEngine->setResult(SAT_VALUE_TRUE);
- return prop::undefSatLiteral;
- }
-
- void addAssertions(const std::vector<Node> &assertions,
- unsigned assertionsEnd,
- IteSkolemMap iteSkolemMap) {
- Trace("decision")
- << "Relevancy::addAssertions()"
- << " size = " << assertions.size()
- << " assertionsEnd = " << assertionsEnd
- << std::endl;
-
- // Save mapping between ite skolems and ite assertions
- for(IteSkolemMap::iterator i = iteSkolemMap.begin();
- i != iteSkolemMap.end(); ++i) {
- Assert(i->second >= assertionsEnd && i->second < assertions.size());
- Debug("jh-ite") << " jh-ite: " << (i->first) << " maps to "
- << assertions[(i->second)] << std::endl;
- d_iteAssertions[i->first] = assertions[i->second];
- }
-
- // Save the 'real' assertions locally
- for(unsigned i = 0; i < assertionsEnd; ++i) {
- d_assertions.push_back(assertions[i]);
- d_visited.clear();
- if(options::decisionComputeRelevancy()) increaseMaxRelevancy(assertions[i]);
- d_visited.clear();
- }
-
- }
-
- bool isRelevant(TNode n) {
- Trace("decision") << "isRelevant(" << n << "): ";
-
- if(Debug.isOn("decision")) {
- if(d_maxRelevancy.find(n) == d_maxRelevancy.end()) {
- // we are becuase of not getting information about literals
- // created using newLiteral command... need to figure how to
- // handle that
- Message() << "isRelevant: WARNING: didn't find node when we should had" << std::endl;
- }
- }
-
- if(d_maxRelevancy.find(n) == d_maxRelevancy.end()) {
- Trace("decision") << "yes [not found in db]" << std::endl;
- return true;
- }
-
- if(options::decisionRelevancyLeaves() && !isAtomicFormula(n)) {
- Trace("decision") << "no [not a leaf]" << std::endl;
- return false;
- }
-
- Trace("decision") << (d_maxRelevancy[n] == d_relevancy[n] ? "no":"yes")
- << std::endl;
-
- Debug("decision") << " maxRel: " << (d_maxRelevancy[n] )
- << " rel: " << d_relevancy[n].get() << std::endl;
- // Assert(d_maxRelevancy.find(n) != d_maxRelevancy.end());
- Assert(0 <= d_relevancy[n] && d_relevancy[n] <= d_maxRelevancy[n]);
-
- if(d_maxRelevancy[n] == d_relevancy[n]) {
- ++d_helfulness; // preventedDecisions
- return false;
- } else {
- return true;
- }
- }
-
- SatValue getPolarity(TNode n) {
- Trace("decision") << "getPolarity([" << n.getId() << "]" << n << "): ";
- Assert(n.getKind() != kind::NOT);
- ++d_polqueries;
- PolarityCache::iterator it = d_polarityCache.find(n);
- if(it == d_polarityCache.end()) {
- Trace("decision") << "don't know" << std::endl;
- return SAT_VALUE_UNKNOWN;
- } else {
- ++d_polhelp;
- Trace("decision") << it->second << std::endl;
- return it->second;
- }
- }
-
- /* Compute justified */
- /*bool computeJustified() {
-
- }*/
-private:
- SatLiteral findSplitter(TNode node, SatValue desiredVal)
- {
- bool ret;
- SatLiteral litDecision;
- try {
- // init
- d_curDecision = &litDecision;
-
- // solve
- ret = findSplitterRec(node, desiredVal);
-
- // post
- d_curDecision = NULL;
- }catch(RelGiveUpException &e) {
- return prop::undefSatLiteral;
- }
- if(ret == true) {
- Trace("decision") << "Yippee!!" << std::endl;
- return litDecision;
- } else {
- return undefSatLiteral;
- }
- }
-
- /**
- * Do all the hardwork.
- * Return 'true' if the node cannot be justfied, 'false' it it can be.
- * Sets 'd_curDecision' if unable to justify (depending on the mode)
- * If 'd_computeRelevancy' is on does multiple backtrace
- */
- bool findSplitterRec(TNode node, SatValue value);
- // Functions to make findSplitterRec modular...
- bool handleOrFalse(TNode node, SatValue desiredVal);
- bool handleOrTrue(TNode node, SatValue desiredVal);
- bool handleITE(TNode node, SatValue desiredVal);
-
- /* Helper functions */
- void setJustified(TNode);
- bool checkJustified(TNode);
-
- /* If literal exists corresponding to the node return
- that. Otherwise an UNKNOWN */
- SatValue tryGetSatValue(Node n);
-
- /* Get list of all term-ITEs for the atomic formula v */
- const Relevancy::IteList& getITEs(TNode n);
-
- /* Compute all term-ITEs in a node recursively */
- void computeITEs(TNode n, IteList &l);
-
- /* Checks whether something is an atomic formula or not */
- bool isAtomicFormula(TNode n) {
- return theory::kindToTheoryId(n.getKind()) != theory::THEORY_BOOL;
- }
-
- /** Recursively increase relevancies */
- void updateRelevancy(TNode n) {
- if(d_visited.find(n) != d_visited.end()) return;
-
- Assert(d_relevancy[n] <= d_maxRelevancy[n]);
-
- if(d_relevancy[n] != d_maxRelevancy[n])
- return;
-
- d_visited.insert(n);
- if(isAtomicFormula(n)) {
- const IteList& l = getITEs(n);
- for(unsigned i = 0; i < l.size(); ++i) {
- if(d_visited.find(l[i]) == d_visited.end()) continue;
- d_relevancy[l[i]] = d_relevancy[l[i]] + 1;
- updateRelevancy(l[i]);
- }
- } else {
- for(unsigned i = 0; i < n.getNumChildren(); ++i) {
- if(d_visited.find(n[i]) == d_visited.end()) continue;
- d_relevancy[n[i]] = d_relevancy[n[i]] + 1;
- updateRelevancy(n[i]);
- }
- }
- d_visited.erase(n);
- }
-
- /* */
- void increaseMaxRelevancy(TNode n) {
-
- Debug("decision")
- << "increaseMaxRelevancy([" << n.getId() << "]" << n << ")"
- << std::endl;
-
- d_maxRelevancy[n]++;
-
- // don't update children multiple times
- if(d_visited.find(n) != d_visited.end()) return;
-
- d_visited.insert(n);
- // Part to make the recursive call
- if(isAtomicFormula(n)) {
- const IteList& l = getITEs(n);
- for(unsigned i = 0; i < l.size(); ++i)
- if(d_visited.find(l[i]) == d_visited.end())
- increaseMaxRelevancy(l[i]);
- } else {
- for(unsigned i = 0; i < n.getNumChildren(); ++i)
- increaseMaxRelevancy(n[i]);
- } //else (...atomic formula...)
- }
-
-};/* class Relevancy */
-
-}/* namespace decision */
-
-}/* namespace CVC4 */
-
-#endif /* __CVC4__DECISION__RELEVANCY */
diff --git a/src/expr/attribute.h b/src/expr/attribute.h
index 70f04be85..721a09403 100644
--- a/src/expr/attribute.h
+++ b/src/expr/attribute.h
@@ -446,7 +446,7 @@ struct HasAttribute<false, AttrKind> {
static inline bool hasAttribute(const AttributeManager* am,
NodeValue* nv) {
typedef typename AttrKind::value_type value_type;
- typedef KindValueToTableValueMapping<value_type> mapping;
+ //typedef KindValueToTableValueMapping<value_type> mapping;
typedef typename getTable<value_type, AttrKind::context_dependent>::
table_type table_type;
@@ -522,14 +522,14 @@ AttributeManager::setAttribute(NodeValue* nv,
template <class T>
inline void AttributeManager::deleteFromTable(AttrHash<T>& table,
NodeValue* nv) {
- for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::s_id; ++id) {
+ for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::getId(); ++id) {
typedef AttributeTraits<T, false> traits_t;
typedef AttrHash<T> hash_t;
std::pair<uint64_t, NodeValue*> pr = std::make_pair(id, nv);
- if(traits_t::cleanup[id] != NULL) {
+ if(traits_t::getCleanup()[id] != NULL) {
typename hash_t::iterator i = table.find(pr);
if(i != table.end()) {
- traits_t::cleanup[id]((*i).second);
+ traits_t::getCleanup()[id]((*i).second);
table.erase(pr);
}
} else {
@@ -544,7 +544,7 @@ inline void AttributeManager::deleteFromTable(AttrHash<T>& table,
template <class T>
inline void AttributeManager::deleteFromTable(CDAttrHash<T>& table,
NodeValue* nv) {
- for(unsigned id = 0; id < attr::LastAttributeId<T, true>::s_id; ++id) {
+ for(unsigned id = 0; id < attr::LastAttributeId<T, true>::getId(); ++id) {
table.obliterate(std::make_pair(id, nv));
}
}
@@ -558,8 +558,8 @@ inline void AttributeManager::deleteAllFromTable(AttrHash<T>& table) {
bool anyRequireClearing = false;
typedef AttributeTraits<T, false> traits_t;
typedef AttrHash<T> hash_t;
- for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::s_id; ++id) {
- if(traits_t::cleanup[id] != NULL) {
+ for(uint64_t id = 0; id < attr::LastAttributeId<T, false>::getId(); ++id) {
+ if(traits_t::getCleanup()[id] != NULL) {
anyRequireClearing = true;
}
}
@@ -575,8 +575,8 @@ inline void AttributeManager::deleteAllFromTable(AttrHash<T>& table) {
<< " node_value: " << ((*it).first.second)
<< std::endl;
*/
- if(traits_t::cleanup[id] != NULL) {
- traits_t::cleanup[id]((*it).second);
+ if(traits_t::getCleanup()[id] != NULL) {
+ traits_t::getCleanup()[id]((*it).second);
}
++it;
}
diff --git a/src/expr/attribute_internals.h b/src/expr/attribute_internals.h
index 4893075c3..a0086440b 100644
--- a/src/expr/attribute_internals.h
+++ b/src/expr/attribute_internals.h
@@ -679,13 +679,12 @@ namespace attr {
*/
template <class T, bool context_dep>
struct LastAttributeId {
- static uint64_t s_id;
+ static uint64_t& getId() {
+ static uint64_t s_id = 0;
+ return s_id;
+ }
};
-/** Initially zero. */
-template <class T, bool context_dep>
-uint64_t LastAttributeId<T, context_dep>::s_id = 0;
-
}/* CVC4::expr::attr namespace */
// ATTRIBUTE TRAITS ============================================================
@@ -699,13 +698,12 @@ namespace attr {
template <class T, bool context_dep>
struct AttributeTraits {
typedef void (*cleanup_t)(T);
- static std::vector<cleanup_t> cleanup;
+ static std::vector<cleanup_t>& getCleanup() {
+ static std::vector<cleanup_t> cleanup;
+ return cleanup;
+ }
};
-template <class T, bool context_dep>
-std::vector<typename AttributeTraits<T, context_dep>::cleanup_t>
- AttributeTraits<T, context_dep>::cleanup;
-
}/* CVC4::expr::attr namespace */
// ATTRIBUTE DEFINITION ========================================================
@@ -765,9 +763,9 @@ public:
typedef typename attr::KindValueToTableValueMapping<value_t>::
table_value_type table_value_type;
typedef attr::AttributeTraits<table_value_type, context_dep> traits;
- uint64_t id = attr::LastAttributeId<table_value_type, context_dep>::s_id++;
- //Assert(traits::cleanup.size() == id);// sanity check
- traits::cleanup.push_back(attr::getCleanupStrategy<value_t,
+ uint64_t id = attr::LastAttributeId<table_value_type, context_dep>::getId()++;
+ Assert(traits::getCleanup().size() == id);// sanity check
+ traits::getCleanup().push_back(attr::getCleanupStrategy<value_t,
CleanupStrategy>::fn);
return id;
}
@@ -827,7 +825,7 @@ public:
* return the id.
*/
static inline uint64_t registerAttribute() {
- uint64_t id = attr::LastAttributeId<bool, context_dep>::s_id++;
+ uint64_t id = attr::LastAttributeId<bool, context_dep>::getId()++;
AlwaysAssert( id <= 63,
"Too many boolean node attributes registered "
"during initialization !" );
@@ -876,7 +874,7 @@ template <class T, class value_t, class CleanupStrategy, bool context_dep>
const uint64_t Attribute<T, value_t, CleanupStrategy, context_dep>::s_id =
( attr::AttributeTraits<typename attr::KindValueToTableValueMapping<value_t>::
table_value_type,
- context_dep>::cleanup.size(),
+ context_dep>::getCleanup().size(),
Attribute<T, value_t, CleanupStrategy, context_dep>::registerAttribute() );
/** Assign unique IDs to attributes at load time. */
diff --git a/src/expr/command.cpp b/src/expr/command.cpp
index 3a88a6cba..8ae448657 100644
--- a/src/expr/command.cpp
+++ b/src/expr/command.cpp
@@ -100,7 +100,7 @@ bool Command::fail() const throw() {
void Command::invoke(SmtEngine* smtEngine, std::ostream& out) throw() {
invoke(smtEngine);
if(!(isMuted() && ok())) {
- printResult(out);
+ printResult(out, smtEngine->getOption("command-verbosity:" + getCommandName()).getIntegerValue().toUnsignedInt());
}
}
@@ -119,9 +119,11 @@ void CommandStatus::toStream(std::ostream& out, OutputLanguage language) const t
Printer::getPrinter(language)->toStream(out, this);
}
-void Command::printResult(std::ostream& out) const throw() {
+void Command::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(d_commandStatus != NULL) {
- out << *d_commandStatus;
+ if((!ok() && verbosity >= 1) || verbosity >= 2) {
+ out << *d_commandStatus;
+ }
}
}
@@ -148,6 +150,10 @@ Command* EmptyCommand::clone() const {
return new EmptyCommand(d_name);
}
+std::string EmptyCommand::getCommandName() const throw() {
+ return "empty";
+}
+
/* class EchoCommand */
EchoCommand::EchoCommand(std::string output) throw() :
@@ -166,7 +172,7 @@ void EchoCommand::invoke(SmtEngine* smtEngine) throw() {
void EchoCommand::invoke(SmtEngine* smtEngine, std::ostream& out) throw() {
out << d_output << std::endl;
d_commandStatus = CommandSuccess::instance();
- printResult(out);
+ printResult(out, smtEngine->getOption("command-verbosity:" + getCommandName()).getIntegerValue().toUnsignedInt());
}
Command* EchoCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
@@ -177,6 +183,10 @@ Command* EchoCommand::clone() const {
return new EchoCommand(d_output);
}
+std::string EchoCommand::getCommandName() const throw() {
+ return "echo";
+}
+
/* class AssertCommand */
AssertCommand::AssertCommand(const Expr& e) throw() :
@@ -204,6 +214,11 @@ Command* AssertCommand::clone() const {
return new AssertCommand(d_expr);
}
+std::string AssertCommand::getCommandName() const throw() {
+ return "assert";
+}
+
+
/* class PushCommand */
void PushCommand::invoke(SmtEngine* smtEngine) throw() {
@@ -223,6 +238,10 @@ Command* PushCommand::clone() const {
return new PushCommand();
}
+std::string PushCommand::getCommandName() const throw() {
+ return "push";
+}
+
/* class PopCommand */
void PopCommand::invoke(SmtEngine* smtEngine) throw() {
@@ -242,6 +261,10 @@ Command* PopCommand::clone() const {
return new PopCommand();
}
+std::string PopCommand::getCommandName() const throw() {
+ return "pop";
+}
+
/* class CheckSatCommand */
CheckSatCommand::CheckSatCommand() throw() :
@@ -269,9 +292,9 @@ Result CheckSatCommand::getResult() const throw() {
return d_result;
}
-void CheckSatCommand::printResult(std::ostream& out) const throw() {
+void CheckSatCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -289,6 +312,10 @@ Command* CheckSatCommand::clone() const {
return c;
}
+std::string CheckSatCommand::getCommandName() const throw() {
+ return "check-sat";
+}
+
/* class QueryCommand */
QueryCommand::QueryCommand(const Expr& e) throw() :
@@ -312,9 +339,9 @@ Result QueryCommand::getResult() const throw() {
return d_result;
}
-void QueryCommand::printResult(std::ostream& out) const throw() {
+void QueryCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -332,6 +359,10 @@ Command* QueryCommand::clone() const {
return c;
}
+std::string QueryCommand::getCommandName() const throw() {
+ return "query";
+}
+
/* class QuitCommand */
QuitCommand::QuitCommand() throw() {
@@ -350,6 +381,10 @@ Command* QuitCommand::clone() const {
return new QuitCommand();
}
+std::string QuitCommand::getCommandName() const throw() {
+ return "exit";
+}
+
/* class CommentCommand */
CommentCommand::CommentCommand(std::string comment) throw() : d_comment(comment) {
@@ -372,6 +407,10 @@ Command* CommentCommand::clone() const {
return new CommentCommand(d_comment);
}
+std::string CommentCommand::getCommandName() const throw() {
+ return "comment";
+}
+
/* class CommandSequence */
CommandSequence::CommandSequence() throw() :
@@ -422,16 +461,13 @@ void CommandSequence::invoke(SmtEngine* smtEngine, std::ostream& out) throw() {
d_commandStatus = CommandSuccess::instance();
}
-CommandSequence::const_iterator CommandSequence::begin() const throw() {
- return d_commandSequence.begin();
-}
-
Command* CommandSequence::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
CommandSequence* seq = new CommandSequence();
for(iterator i = begin(); i != end(); ++i) {
Command* cmd_to_export = *i;
Command* cmd = cmd_to_export->exportTo(exprManager, variableMap);
seq->addCommand(cmd);
+ Debug("export") << "[export] so far coverted: " << seq << endl;
}
seq->d_index = d_index;
return seq;
@@ -446,6 +482,10 @@ Command* CommandSequence::clone() const {
return seq;
}
+CommandSequence::const_iterator CommandSequence::begin() const throw() {
+ return d_commandSequence.begin();
+}
+
CommandSequence::const_iterator CommandSequence::end() const throw() {
return d_commandSequence.end();
}
@@ -458,6 +498,10 @@ CommandSequence::iterator CommandSequence::end() throw() {
return d_commandSequence.end();
}
+std::string CommandSequence::getCommandName() const throw() {
+ return "sequence";
+}
+
/* class DeclarationSequenceCommand */
/* class DeclarationDefinitionCommand */
@@ -500,6 +544,10 @@ Command* DeclareFunctionCommand::clone() const {
return new DeclareFunctionCommand(d_symbol, d_func, d_type);
}
+std::string DeclareFunctionCommand::getCommandName() const throw() {
+ return "declare-fun";
+}
+
/* class DeclareTypeCommand */
DeclareTypeCommand::DeclareTypeCommand(const std::string& id, size_t arity, Type t) throw() :
@@ -530,6 +578,10 @@ Command* DeclareTypeCommand::clone() const {
return new DeclareTypeCommand(d_symbol, d_arity, d_type);
}
+std::string DeclareTypeCommand::getCommandName() const throw() {
+ return "declare-sort";
+}
+
/* class DefineTypeCommand */
DefineTypeCommand::DefineTypeCommand(const std::string& id,
@@ -571,6 +623,10 @@ Command* DefineTypeCommand::clone() const {
return new DefineTypeCommand(d_symbol, d_params, d_type);
}
+std::string DefineTypeCommand::getCommandName() const throw() {
+ return "define-sort";
+}
+
/* class DefineFunctionCommand */
DefineFunctionCommand::DefineFunctionCommand(const std::string& id,
@@ -616,7 +672,7 @@ void DefineFunctionCommand::invoke(SmtEngine* smtEngine) throw() {
}
Command* DefineFunctionCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- Expr func = d_func.exportTo(exprManager, variableMap);
+ Expr func = d_func.exportTo(exprManager, variableMap, /* flags = */ ExprManager::VAR_FLAG_DEFINED);
vector<Expr> formals;
transform(d_formals.begin(), d_formals.end(), back_inserter(formals),
ExportTransformer(exprManager, variableMap));
@@ -628,6 +684,10 @@ Command* DefineFunctionCommand::clone() const {
return new DefineFunctionCommand(d_symbol, d_func, d_formals, d_formula);
}
+std::string DefineFunctionCommand::getCommandName() const throw() {
+ return "define-fun";
+}
+
/* class DefineNamedFunctionCommand */
DefineNamedFunctionCommand::DefineNamedFunctionCommand(const std::string& id,
@@ -695,6 +755,10 @@ Command* SetUserAttributeCommand::clone() const{
return new SetUserAttributeCommand( d_attr, d_expr );
}
+std::string SetUserAttributeCommand::getCommandName() const throw() {
+ return "set-user-attribute";
+}
+
/* class SimplifyCommand */
SimplifyCommand::SimplifyCommand(Expr term) throw() :
@@ -718,9 +782,9 @@ Expr SimplifyCommand::getResult() const throw() {
return d_result;
}
-void SimplifyCommand::printResult(std::ostream& out) const throw() {
+void SimplifyCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -738,6 +802,10 @@ Command* SimplifyCommand::clone() const {
return c;
}
+std::string SimplifyCommand::getCommandName() const throw() {
+ return "simplify";
+}
+
/* class ExpandDefinitionsCommand */
ExpandDefinitionsCommand::ExpandDefinitionsCommand(Expr term) throw() :
@@ -757,9 +825,9 @@ Expr ExpandDefinitionsCommand::getResult() const throw() {
return d_result;
}
-void ExpandDefinitionsCommand::printResult(std::ostream& out) const throw() {
+void ExpandDefinitionsCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -777,6 +845,10 @@ Command* ExpandDefinitionsCommand::clone() const {
return c;
}
+std::string ExpandDefinitionsCommand::getCommandName() const throw() {
+ return "expand-definitions";
+}
+
/* class GetValueCommand */
GetValueCommand::GetValueCommand(Expr term) throw() :
@@ -795,17 +867,17 @@ const std::vector<Expr>& GetValueCommand::getTerms() const throw() {
void GetValueCommand::invoke(SmtEngine* smtEngine) throw() {
try {
- vector<Node> result;
- NodeManager* nm = NodeManager::fromExprManager(smtEngine->getExprManager());
+ vector<Expr> result;
+ ExprManager* em = smtEngine->getExprManager();
+ NodeManager* nm = NodeManager::fromExprManager(em);
for(std::vector<Expr>::const_iterator i = d_terms.begin(); i != d_terms.end(); ++i) {
Assert(nm == NodeManager::fromExprManager((*i).getExprManager()));
smt::SmtScope scope(smtEngine);
Node request = Node::fromExpr(options::expandDefinitions() ? smtEngine->expandDefinitions(*i) : *i);
Node value = Node::fromExpr(smtEngine->getValue(*i));
- result.push_back(nm->mkNode(kind::SEXPR, request, value));
+ result.push_back(nm->mkNode(kind::SEXPR, request, value).toExpr());
}
- Node n = nm->mkNode(kind::SEXPR, result);
- d_result = nm->toExpr(n);
+ d_result = em->mkExpr(kind::SEXPR, result);
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
@@ -816,9 +888,9 @@ Expr GetValueCommand::getResult() const throw() {
return d_result;
}
-void GetValueCommand::printResult(std::ostream& out) const throw() {
+void GetValueCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
Expr::dag::Scope scope(out, false);
out << d_result << endl;
@@ -841,6 +913,10 @@ Command* GetValueCommand::clone() const {
return c;
}
+std::string GetValueCommand::getCommandName() const throw() {
+ return "get-value";
+}
+
/* class GetAssignmentCommand */
GetAssignmentCommand::GetAssignmentCommand() throw() {
@@ -859,9 +935,9 @@ SExpr GetAssignmentCommand::getResult() const throw() {
return d_result;
}
-void GetAssignmentCommand::printResult(std::ostream& out) const throw() {
+void GetAssignmentCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result << endl;
}
@@ -879,6 +955,10 @@ Command* GetAssignmentCommand::clone() const {
return c;
}
+std::string GetAssignmentCommand::getCommandName() const throw() {
+ return "get-assignment";
+}
+
/* class GetModelCommand */
GetModelCommand::GetModelCommand() throw() {
@@ -900,9 +980,9 @@ Model* GetModelCommand::getResult() const throw() {
}
*/
-void GetModelCommand::printResult(std::ostream& out) const throw() {
+void GetModelCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << *d_result;
}
@@ -922,6 +1002,10 @@ Command* GetModelCommand::clone() const {
return c;
}
+std::string GetModelCommand::getCommandName() const throw() {
+ return "get-model";
+}
+
/* class GetProofCommand */
GetProofCommand::GetProofCommand() throw() {
@@ -940,9 +1024,9 @@ Proof* GetProofCommand::getResult() const throw() {
return d_result;
}
-void GetProofCommand::printResult(std::ostream& out) const throw() {
+void GetProofCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
d_result->toStream(out);
}
@@ -960,6 +1044,10 @@ Command* GetProofCommand::clone() const {
return c;
}
+std::string GetProofCommand::getCommandName() const throw() {
+ return "get-proof";
+}
+
/* class GetUnsatCoreCommand */
GetUnsatCoreCommand::GetUnsatCoreCommand() throw() {
@@ -977,9 +1065,9 @@ void GetUnsatCoreCommand::invoke(SmtEngine* smtEngine) throw() {
d_commandStatus = new CommandUnsupported();
}
-void GetUnsatCoreCommand::printResult(std::ostream& out) const throw() {
+void GetUnsatCoreCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
//do nothing -- unsat cores not yet supported
// d_result->toStream(out);
@@ -998,6 +1086,10 @@ Command* GetUnsatCoreCommand::clone() const {
return c;
}
+std::string GetUnsatCoreCommand::getCommandName() const throw() {
+ return "get-unsat-core";
+}
+
/* class GetAssertionsCommand */
GetAssertionsCommand::GetAssertionsCommand() throw() {
@@ -1021,9 +1113,9 @@ std::string GetAssertionsCommand::getResult() const throw() {
return d_result;
}
-void GetAssertionsCommand::printResult(std::ostream& out) const throw() {
+void GetAssertionsCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else {
out << d_result;
}
@@ -1041,6 +1133,10 @@ Command* GetAssertionsCommand::clone() const {
return c;
}
+std::string GetAssertionsCommand::getCommandName() const throw() {
+ return "get-assertions";
+}
+
/* class SetBenchmarkStatusCommand */
SetBenchmarkStatusCommand::SetBenchmarkStatusCommand(BenchmarkStatus status) throw() :
@@ -1071,6 +1167,10 @@ Command* SetBenchmarkStatusCommand::clone() const {
return new SetBenchmarkStatusCommand(d_status);
}
+std::string SetBenchmarkStatusCommand::getCommandName() const throw() {
+ return "set-info";
+}
+
/* class SetBenchmarkLogicCommand */
SetBenchmarkLogicCommand::SetBenchmarkLogicCommand(std::string logic) throw() :
@@ -1098,6 +1198,10 @@ Command* SetBenchmarkLogicCommand::clone() const {
return new SetBenchmarkLogicCommand(d_logic);
}
+std::string SetBenchmarkLogicCommand::getCommandName() const throw() {
+ return "set-logic";
+}
+
/* class SetInfoCommand */
SetInfoCommand::SetInfoCommand(std::string flag, const SExpr& sexpr) throw() :
@@ -1118,7 +1222,8 @@ void SetInfoCommand::invoke(SmtEngine* smtEngine) throw() {
smtEngine->setInfo(d_flag, d_sexpr);
d_commandStatus = CommandSuccess::instance();
} catch(UnrecognizedOptionException&) {
- d_commandStatus = new CommandUnsupported();
+ // As per SMT-LIB spec, silently accept unknown set-info keys
+ d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
}
@@ -1132,6 +1237,10 @@ Command* SetInfoCommand::clone() const {
return new SetInfoCommand(d_flag, d_sexpr);
}
+std::string SetInfoCommand::getCommandName() const throw() {
+ return "set-info";
+}
+
/* class GetInfoCommand */
GetInfoCommand::GetInfoCommand(std::string flag) throw() :
@@ -1162,9 +1271,9 @@ std::string GetInfoCommand::getResult() const throw() {
return d_result;
}
-void GetInfoCommand::printResult(std::ostream& out) const throw() {
+void GetInfoCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else if(d_result != "") {
out << d_result << endl;
}
@@ -1182,6 +1291,10 @@ Command* GetInfoCommand::clone() const {
return c;
}
+std::string GetInfoCommand::getCommandName() const throw() {
+ return "get-info";
+}
+
/* class SetOptionCommand */
SetOptionCommand::SetOptionCommand(std::string flag, const SExpr& sexpr) throw() :
@@ -1216,6 +1329,10 @@ Command* SetOptionCommand::clone() const {
return new SetOptionCommand(d_flag, d_sexpr);
}
+std::string SetOptionCommand::getCommandName() const throw() {
+ return "set-option";
+}
+
/* class GetOptionCommand */
GetOptionCommand::GetOptionCommand(std::string flag) throw() :
@@ -1228,11 +1345,9 @@ std::string GetOptionCommand::getFlag() const throw() {
void GetOptionCommand::invoke(SmtEngine* smtEngine) throw() {
try {
- vector<SExpr> v;
- v.push_back(SExpr(SExpr::Keyword(string(":") + d_flag)));
- v.push_back(smtEngine->getOption(d_flag));
+ SExpr res = smtEngine->getOption(d_flag);
stringstream ss;
- ss << SExpr(v);
+ ss << res;
d_result = ss.str();
d_commandStatus = CommandSuccess::instance();
} catch(UnrecognizedOptionException&) {
@@ -1246,9 +1361,9 @@ std::string GetOptionCommand::getResult() const throw() {
return d_result;
}
-void GetOptionCommand::printResult(std::ostream& out) const throw() {
+void GetOptionCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
- this->Command::printResult(out);
+ this->Command::printResult(out, verbosity);
} else if(d_result != "") {
out << d_result << endl;
}
@@ -1266,6 +1381,10 @@ Command* GetOptionCommand::clone() const {
return c;
}
+std::string GetOptionCommand::getCommandName() const throw() {
+ return "get-option";
+}
+
/* class DatatypeDeclarationCommand */
DatatypeDeclarationCommand::DatatypeDeclarationCommand(const DatatypeType& datatype) throw() :
@@ -1295,6 +1414,10 @@ Command* DatatypeDeclarationCommand::clone() const {
return new DatatypeDeclarationCommand(d_datatypes);
}
+std::string DatatypeDeclarationCommand::getCommandName() const throw() {
+ return "declare-datatypes";
+}
+
/* class RewriteRuleCommand */
RewriteRuleCommand::RewriteRuleCommand(const std::vector<Expr>& vars,
@@ -1395,6 +1518,10 @@ Command* RewriteRuleCommand::clone() const {
return new RewriteRuleCommand(d_vars, d_guards, d_head, d_body, d_triggers);
}
+std::string RewriteRuleCommand::getCommandName() const throw() {
+ return "rewrite-rule";
+}
+
/* class PropagateRuleCommand */
PropagateRuleCommand::PropagateRuleCommand(const std::vector<Expr>& vars,
@@ -1512,6 +1639,10 @@ Command* PropagateRuleCommand::clone() const {
return new PropagateRuleCommand(d_vars, d_guards, d_heads, d_body, d_triggers);
}
+std::string PropagateRuleCommand::getCommandName() const throw() {
+ return "propagate-rule";
+}
+
/* output stream insertion operator for benchmark statuses */
std::ostream& operator<<(std::ostream& out,
BenchmarkStatus status) throw() {
diff --git a/src/expr/command.h b/src/expr/command.h
index 38a8b1efa..a3d58e5dd 100644
--- a/src/expr/command.h
+++ b/src/expr/command.h
@@ -215,6 +215,8 @@ public:
std::string toString() const throw();
+ virtual std::string getCommandName() const throw() = 0;
+
/**
* If false, instruct this Command not to print a success message.
*/
@@ -240,7 +242,7 @@ public:
/** Get the command status (it's NULL if we haven't run yet). */
const CommandStatus* getCommandStatus() const throw() { return d_commandStatus; }
- virtual void printResult(std::ostream& out) const throw();
+ virtual void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
/**
* Maps this Command into one for a different ExprManager, using
@@ -287,6 +289,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class EmptyCommand */
class CVC4_PUBLIC EchoCommand : public Command {
@@ -300,6 +303,7 @@ public:
void invoke(SmtEngine* smtEngine, std::ostream& out) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class EchoCommand */
class CVC4_PUBLIC AssertCommand : public Command {
@@ -312,6 +316,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class AssertCommand */
class CVC4_PUBLIC PushCommand : public Command {
@@ -320,6 +325,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class PushCommand */
class CVC4_PUBLIC PopCommand : public Command {
@@ -328,6 +334,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class PopCommand */
class CVC4_PUBLIC DeclarationDefinitionCommand : public Command {
@@ -352,6 +359,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DeclareFunctionCommand */
class CVC4_PUBLIC DeclareTypeCommand : public DeclarationDefinitionCommand {
@@ -366,6 +374,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DeclareTypeCommand */
class CVC4_PUBLIC DefineTypeCommand : public DeclarationDefinitionCommand {
@@ -381,6 +390,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DefineTypeCommand */
class CVC4_PUBLIC DefineFunctionCommand : public DeclarationDefinitionCommand {
@@ -399,6 +409,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DefineFunctionCommand */
/**
@@ -433,6 +444,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetUserAttributeCommand */
@@ -447,9 +459,10 @@ public:
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
Result getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class CheckSatCommand */
class CVC4_PUBLIC QueryCommand : public Command {
@@ -462,9 +475,10 @@ public:
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
Result getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class QueryCommand */
// this is TRANSFORM in the CVC presentation language
@@ -478,9 +492,10 @@ public:
Expr getTerm() const throw();
void invoke(SmtEngine* smtEngine) throw();
Expr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SimplifyCommand */
class CVC4_PUBLIC ExpandDefinitionsCommand : public Command {
@@ -493,9 +508,10 @@ public:
Expr getTerm() const throw();
void invoke(SmtEngine* smtEngine) throw();
Expr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class ExpandDefinitionsCommand */
class CVC4_PUBLIC GetValueCommand : public Command {
@@ -509,9 +525,10 @@ public:
const std::vector<Expr>& getTerms() const throw();
void invoke(SmtEngine* smtEngine) throw();
Expr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetValueCommand */
class CVC4_PUBLIC GetAssignmentCommand : public Command {
@@ -522,9 +539,10 @@ public:
~GetAssignmentCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
SExpr getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetAssignmentCommand */
class CVC4_PUBLIC GetModelCommand : public Command {
@@ -537,9 +555,10 @@ public:
void invoke(SmtEngine* smtEngine) throw();
// Model is private to the library -- for now
//Model* getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetModelCommand */
class CVC4_PUBLIC GetProofCommand : public Command {
@@ -550,9 +569,10 @@ public:
~GetProofCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
Proof* getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetProofCommand */
class CVC4_PUBLIC GetUnsatCoreCommand : public Command {
@@ -562,9 +582,10 @@ public:
GetUnsatCoreCommand() throw();
~GetUnsatCoreCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetUnsatCoreCommand */
class CVC4_PUBLIC GetAssertionsCommand : public Command {
@@ -575,9 +596,10 @@ public:
~GetAssertionsCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
std::string getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetAssertionsCommand */
class CVC4_PUBLIC SetBenchmarkStatusCommand : public Command {
@@ -590,6 +612,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetBenchmarkStatusCommand */
class CVC4_PUBLIC SetBenchmarkLogicCommand : public Command {
@@ -602,6 +625,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetBenchmarkLogicCommand */
class CVC4_PUBLIC SetInfoCommand : public Command {
@@ -616,6 +640,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetInfoCommand */
class CVC4_PUBLIC GetInfoCommand : public Command {
@@ -628,9 +653,10 @@ public:
std::string getFlag() const throw();
void invoke(SmtEngine* smtEngine) throw();
std::string getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetInfoCommand */
class CVC4_PUBLIC SetOptionCommand : public Command {
@@ -645,6 +671,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class SetOptionCommand */
class CVC4_PUBLIC GetOptionCommand : public Command {
@@ -657,9 +684,10 @@ public:
std::string getFlag() const throw();
void invoke(SmtEngine* smtEngine) throw();
std::string getResult() const throw();
- void printResult(std::ostream& out) const throw();
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class GetOptionCommand */
class CVC4_PUBLIC DatatypeDeclarationCommand : public Command {
@@ -673,6 +701,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class DatatypeDeclarationCommand */
class CVC4_PUBLIC RewriteRuleCommand : public Command {
@@ -703,6 +732,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class RewriteRuleCommand */
class CVC4_PUBLIC PropagateRuleCommand : public Command {
@@ -738,6 +768,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class PropagateRuleCommand */
@@ -748,6 +779,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class QuitCommand */
class CVC4_PUBLIC CommentCommand : public Command {
@@ -759,6 +791,7 @@ public:
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class CommentCommand */
class CVC4_PUBLIC CommandSequence : public Command {
@@ -788,6 +821,7 @@ public:
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
+ std::string getCommandName() const throw();
};/* class CommandSequence */
class CVC4_PUBLIC DeclarationSequence : public CommandSequence {
diff --git a/src/expr/expr.i b/src/expr/expr.i
index 977345a63..c649a5ebb 100644
--- a/src/expr/expr.i
+++ b/src/expr/expr.i
@@ -9,7 +9,11 @@
#endif /* SWIGJAVA */
%}
+#ifdef SWIGPYTHON
+%rename(doApply) CVC4::ExprHashFunction::operator()(CVC4::Expr) const;
+#else /* SWIGPYTHON */
%rename(apply) CVC4::ExprHashFunction::operator()(CVC4::Expr) const;
+#endif /* SWIGPYTHON */
%ignore CVC4::operator<<(std::ostream&, const Expr&);
%ignore CVC4::operator<<(std::ostream&, const TypeCheckingException&);
diff --git a/src/expr/expr_manager.i b/src/expr/expr_manager.i
index a386af5ee..a2ff0337a 100644
--- a/src/expr/expr_manager.i
+++ b/src/expr/expr_manager.i
@@ -34,6 +34,10 @@
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::UninterpretedConstant>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::kind::Kind_t>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::Datatype>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::TupleSelect>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::TupleUpdate>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::RecordSelect>;
+%template(mkConst) CVC4::ExprManager::mkConst<CVC4::RecordUpdate>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::Rational>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::BitVector>;
%template(mkConst) CVC4::ExprManager::mkConst<CVC4::Predicate>;
diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp
index 524bc2095..d87c498e6 100644
--- a/src/expr/expr_manager_template.cpp
+++ b/src/expr/expr_manager_template.cpp
@@ -304,8 +304,8 @@ Expr ExprManager::mkExpr(Kind kind, Expr child1, const std::vector<Expr>& otherC
Expr ExprManager::mkExpr(Expr opExpr) {
const unsigned n = 0;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -323,8 +323,8 @@ Expr ExprManager::mkExpr(Expr opExpr) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1) {
const unsigned n = 1;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -342,8 +342,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2) {
const unsigned n = 2;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -363,8 +363,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3) {
const unsigned n = 3;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -386,8 +386,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3) {
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr child4) {
const unsigned n = 4;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -410,8 +410,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr child4, Expr child5) {
const unsigned n = 5;
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -434,8 +434,8 @@ Expr ExprManager::mkExpr(Expr opExpr, Expr child1, Expr child2, Expr child3,
Expr ExprManager::mkExpr(Expr opExpr, const std::vector<Expr>& children) {
const unsigned n = children.size();
- Kind kind = kind::operatorKindToKind(opExpr.getKind());
- CheckArgument(kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
+ Kind kind = NodeManager::operatorToKind(opExpr.getNode());
+ CheckArgument(opExpr.getKind() == kind::BUILTIN || kind::metaKindOf(kind) == kind::metakind::PARAMETERIZED, opExpr,
"This Expr constructor is for parameterized kinds only");
CheckArgument(n >= minArity(kind) && n <= maxArity(kind), kind,
"Exprs with kind %s must have at least %u children and "
@@ -509,7 +509,6 @@ FunctionType ExprManager::mkPredicateType(const std::vector<Type>& sorts) {
TupleType ExprManager::mkTupleType(const std::vector<Type>& types) {
NodeManagerScope nms(d_nodeManager);
- Assert( types.size() >= 1 );
std::vector<TypeNode> typeNodes;
for (unsigned i = 0, i_end = types.size(); i < i_end; ++ i) {
typeNodes.push_back(*types[i].d_typeNode);
@@ -719,9 +718,9 @@ TesterType ExprManager::mkTesterType(Type domain) const {
return Type(d_nodeManager, new TypeNode(d_nodeManager->mkTesterType(*domain.d_typeNode)));
}
-SortType ExprManager::mkSort(const std::string& name) const {
+SortType ExprManager::mkSort(const std::string& name, uint32_t flags) const {
NodeManagerScope nms(d_nodeManager);
- return SortType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkSort(name))));
+ return SortType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkSort(name, flags))));
}
SortConstructorType ExprManager::mkSortConstructor(const std::string& name,
@@ -805,20 +804,20 @@ Type ExprManager::getType(Expr e, bool check) throw (TypeCheckingException) {
return t;
}
-Expr ExprManager::mkVar(const std::string& name, Type type, bool isGlobal) {
+Expr ExprManager::mkVar(const std::string& name, Type type, uint32_t flags) {
Assert(NodeManager::currentNM() == NULL, "ExprManager::mkVar() should only be called externally, not from within CVC4 code. Please use mkSkolem().");
NodeManagerScope nms(d_nodeManager);
- Node* n = d_nodeManager->mkVarPtr(name, *type.d_typeNode, isGlobal);
+ Node* n = d_nodeManager->mkVarPtr(name, *type.d_typeNode, flags);
Debug("nm") << "set " << name << " on " << *n << std::endl;
INC_STAT_VAR(type, false);
return Expr(this, n);
}
-Expr ExprManager::mkVar(Type type, bool isGlobal) {
+Expr ExprManager::mkVar(Type type, uint32_t flags) {
Assert(NodeManager::currentNM() == NULL, "ExprManager::mkVar() should only be called externally, not from within CVC4 code. Please use mkSkolem().");
NodeManagerScope nms(d_nodeManager);
INC_STAT_VAR(type, false);
- return Expr(this, d_nodeManager->mkVarPtr(*type.d_typeNode, isGlobal));
+ return Expr(this, d_nodeManager->mkVarPtr(*type.d_typeNode, flags));
}
Expr ExprManager::mkBoundVar(const std::string& name, Type type) {
diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h
index fd81c9bf8..3f0ec2f9c 100644
--- a/src/expr/expr_manager_template.h
+++ b/src/expr/expr_manager_template.h
@@ -430,8 +430,14 @@ public:
/** Make a type representing a tester with the given parameterization. */
TesterType mkTesterType(Type domain) const;
+ /** Bits for use in mkSort() flags. */
+ enum {
+ SORT_FLAG_NONE = 0,
+ SORT_FLAG_PLACEHOLDER = 1
+ };/* enum */
+
/** Make a new sort with the given name. */
- SortType mkSort(const std::string& name) const;
+ SortType mkSort(const std::string& name, uint32_t flags = SORT_FLAG_NONE) const;
/** Make a sort constructor from a name and arity. */
SortConstructorType mkSortConstructor(const std::string& name,
@@ -468,10 +474,82 @@ public:
Type getType(Expr e, bool check = false)
throw(TypeCheckingException);
- // variables are special, because duplicates are permitted
- Expr mkVar(const std::string& name, Type type, bool isGlobal = false);
- Expr mkVar(Type type, bool isGlobal = false);
+ /** Bits for use in mkVar() flags. */
+ enum {
+ VAR_FLAG_NONE = 0,
+ VAR_FLAG_GLOBAL = 1,
+ VAR_FLAG_DEFINED = 2
+ };/* enum */
+
+ /**
+ * Create a new, fresh variable. This variable is guaranteed to be
+ * distinct from every variable thus far in the ExprManager, even
+ * if it shares a name with another; this is to support any kind of
+ * scoping policy on top of ExprManager. The SymbolTable class
+ * can be used to store and lookup symbols by name, if desired.
+ *
+ * @param name a name to associate to the fresh new variable
+ * @param type the type for the new variable
+ * @param flags - VAR_FLAG_NONE - no flags;
+ * VAR_FLAG_GLOBAL - whether this variable is to be
+ * considered "global" or not. Note that this information isn't
+ * used by the ExprManager, but is passed on to the ExprManager's
+ * event subscribers like the model-building service; if isGlobal
+ * is true, this newly-created variable will still available in
+ * models generated after an intervening pop.
+ * VAR_FLAG_DEFINED - if this is to be a "defined" symbol, e.g., for
+ * use with SmtEngine::defineFunction(). This keeps a declaration
+ * from being emitted in API dumps (since a subsequent definition is
+ * expected to be dumped instead).
+ */
+ Expr mkVar(const std::string& name, Type type, uint32_t flags = VAR_FLAG_NONE);
+
+ /**
+ * Create a (nameless) new, fresh variable. This variable is guaranteed
+ * to be distinct from every variable thus far in the ExprManager.
+ *
+ * @param type the type for the new variable
+ * @param flags - VAR_FLAG_GLOBAL - whether this variable is to be considered "global"
+ * or not. Note that this information isn't used by the ExprManager,
+ * but is passed on to the ExprManager's event subscribers like the
+ * model-building service; if isGlobal is true, this newly-created
+ * variable will still available in models generated after an
+ * intervening pop.
+ */
+ Expr mkVar(Type type, uint32_t flags = VAR_FLAG_NONE);
+
+ /**
+ * Create a new, fresh variable for use in a binder expression
+ * (the BOUND_VAR_LIST of a FORALL, EXISTS, or LAMBDA). It is
+ * an error for this bound variable to exist outside of a binder,
+ * and it should also only be used in a single binder expression.
+ * That is, two distinct FORALL expressions should use entirely
+ * disjoint sets of bound variables (however, a single FORALL
+ * expression can be used in multiple places in a formula without
+ * a problem). This newly-created bound variable is guaranteed to
+ * be distinct from every variable thus far in the ExprManager, even
+ * if it shares a name with another; this is to support any kind of
+ * scoping policy on top of ExprManager. The SymbolTable class
+ * can be used to store and lookup symbols by name, if desired.
+ *
+ * @param name a name to associate to the fresh new bound variable
+ * @param type the type for the new bound variable
+ */
Expr mkBoundVar(const std::string& name, Type type);
+
+ /**
+ * Create a (nameless) new, fresh variable for use in a binder
+ * expression (the BOUND_VAR_LIST of a FORALL, EXISTS, or LAMBDA).
+ * It is an error for this bound variable to exist outside of a
+ * binder, and it should also only be used in a single binder
+ * expression. That is, two distinct FORALL expressions should use
+ * entirely disjoint sets of bound variables (however, a single FORALL
+ * expression can be used in multiple places in a formula without
+ * a problem). This newly-created bound variable is guaranteed to
+ * be distinct from every variable thus far in the ExprManager.
+ *
+ * @param type the type for the new bound variable
+ */
Expr mkBoundVar(Type type);
/** Get a reference to the statistics registry for this ExprManager */
diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp
index 7e809ed62..ad9ec49ac 100644
--- a/src/expr/expr_template.cpp
+++ b/src/expr/expr_template.cpp
@@ -115,7 +115,7 @@ namespace expr {
static Node exportConstant(TNode n, NodeManager* to);
-Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap) {
+Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags) {
if(n.isNull()) return Node::null();
if(theory::kindToTheoryId(n.getKind()) == theory::THEORY_DATATYPES) {
throw ExportUnsupportedException
@@ -146,7 +146,7 @@ Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapC
bool isGlobal;
Node::fromExpr(from_e).getAttribute(GlobalVarAttr(), isGlobal);
NodeManagerScope nullScope(NULL);
- to_e = to->mkVar(name, type, isGlobal);// FIXME thread safety
+ to_e = to->mkVar(name, type, isGlobal ? ExprManager::VAR_FLAG_GLOBAL : flags);// FIXME thread safety
} else if(n.getKind() == kind::SKOLEM) {
// skolems are only available at the Node level (not the Expr level)
TypeNode typeNode = TypeNode::fromType(type);
@@ -178,13 +178,13 @@ Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapC
if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
Debug("export") << "+ parameterized, op is " << n.getOperator() << std::endl;
children.reserve(n.getNumChildren() + 1);
- children.push_back(exportInternal(n.getOperator(), from, to, vmap));
+ children.push_back(exportInternal(n.getOperator(), from, to, vmap, flags));
} else {
children.reserve(n.getNumChildren());
}
for(TNode::iterator i = n.begin(), i_end = n.end(); i != i_end; ++i) {
Debug("export") << "+ child: " << *i << std::endl;
- children.push_back(exportInternal(*i, from, to, vmap));
+ children.push_back(exportInternal(*i, from, to, vmap, flags));
}
if(Debug.isOn("export")) {
ExprManagerScope ems(*to);
@@ -199,11 +199,12 @@ Node exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapC
}/* CVC4::expr namespace */
-Expr Expr::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) const {
+Expr Expr::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap,
+ uint32_t flags /* = 0 */) const {
Assert(d_exprManager != exprManager,
"No sense in cloning an Expr in the same ExprManager");
ExprManagerScope ems(*this);
- return Expr(exprManager, new Node(expr::exportInternal(*d_node, d_exprManager, exprManager, variableMap)));
+ return Expr(exprManager, new Node(expr::exportInternal(*d_node, d_exprManager, exprManager, variableMap, flags)));
}
Expr& Expr::operator=(const Expr& e) {
diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h
index 7772de81e..e262fada8 100644
--- a/src/expr/expr_template.h
+++ b/src/expr/expr_template.h
@@ -81,7 +81,7 @@ namespace expr {
class CVC4_PUBLIC ExprDag;
class CVC4_PUBLIC ExprSetLanguage;
- NodeTemplate<true> exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
+ NodeTemplate<true> exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags);
}/* CVC4::expr namespace */
/**
@@ -510,7 +510,7 @@ public:
* variableMap for the translation and extending it with any new
* mappings.
*/
- Expr exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) const;
+ Expr exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap, uint32_t flags = 0) const;
/**
* IOStream manipulator to set the maximum depth of Exprs when
@@ -591,7 +591,7 @@ private:
friend class TypeCheckingException;
friend class expr::pickle::Pickler;
friend class prop::TheoryProxy;
- friend NodeTemplate<true> expr::exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
+ friend NodeTemplate<true> expr::exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags);
friend std::ostream& CVC4::operator<<(std::ostream& out, const Expr& e);
template <bool ref_count> friend class NodeTemplate;
diff --git a/src/expr/metakind_template.h b/src/expr/metakind_template.h
index 22d7baac3..93cebe00a 100644
--- a/src/expr/metakind_template.h
+++ b/src/expr/metakind_template.h
@@ -126,18 +126,6 @@ ${metakind_kinds}
return metaKinds[k + 1];
}/* metaKindOf(k) */
-/**
- * Map a kind of the operator to the kind of the enclosing expression. For
- * example, since the kind of functions is just VARIABLE, it should map
- * VARIABLE to APPLY_UF.
- */
-static inline Kind operatorKindToKind(Kind k) {
- switch (k) {
-${metakind_operatorKinds}
- default:
- return kind::UNDEFINED_KIND; /* LAST_KIND */
- };
-}
}/* CVC4::kind namespace */
namespace expr {
@@ -282,6 +270,13 @@ inline void NodeValueConstPrinter::toStream(std::ostream& out, TNode n) {
toStream(out, n.d_nv);
}
+// The reinterpret_cast of d_children to various constant payload types
+// in deleteNodeValueConstant(), below, can flag a "strict aliasing"
+// warning; it should actually be okay, because we never access the
+// embedded constant as a NodeValue* child, and never access an embedded
+// NodeValue* child as a constant.
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+
/**
* Cleanup to be performed when a NodeValue zombie is collected, and
* it has CONSTANT metakind. This calls the destructor for the underlying
@@ -301,6 +296,9 @@ ${metakind_constDeleters}
}
}
+// re-enable the strict-aliasing warning
+# pragma GCC diagnostic warning "-Wstrict-aliasing"
+
inline unsigned getLowerBoundForKind(::CVC4::Kind k) {
static const unsigned lbs[] = {
0, /* NULL_EXPR */
@@ -324,9 +322,30 @@ ${metakind_ubchildren}
}
}/* CVC4::kind::metakind namespace */
+
+/**
+ * Map a kind of the operator to the kind of the enclosing expression. For
+ * example, since the kind of functions is just VARIABLE, it should map
+ * VARIABLE to APPLY_UF.
+ */
+static inline Kind operatorToKind(::CVC4::expr::NodeValue* nv) {
+ if(nv->getKind() == kind::BUILTIN) {
+ return nv->getConst<Kind>();
+ } else if(nv->getKind() == kind::LAMBDA) {
+ return kind::APPLY_UF;
+ }
+
+ switch(Kind k CVC4_UNUSED = nv->getKind()) {
+${metakind_operatorKinds}
+
+ default:
+ return kind::UNDEFINED_KIND; /* LAST_KIND */
+ };
+}
+
}/* CVC4::kind namespace */
-#line 330 "${template}"
+#line 349 "${template}"
namespace theory {
diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind
index d8192e432..7ffe0230b 100755
--- a/src/expr/mkmetakind
+++ b/src/expr/mkmetakind
@@ -303,8 +303,9 @@ struct ConstantMapReverse< ::CVC4::kind::$1 > {
function registerOperatorToKind {
operatorKind=$1
applyKind=$2
- metakind_operatorKinds="${metakind_operatorKinds} case kind::$applyKind: return kind::$operatorKind;
-";
+ metakind_operatorKinds="${metakind_operatorKinds}
+#line $lineno \"$kf\"
+ case kind::$applyKind: return kind::$operatorKind;";
}
function register_metakind {
@@ -381,8 +382,8 @@ while [ $# -gt 0 ]; do
/* from $b */
"
metakind_operatorKinds="${metakind_operatorKinds}
- /* from $b */
-"
+
+ /* from $b */"
source "$kf"
if ! $seen_theory; then
echo "$kf: error: no theory content found in file!" >&2
diff --git a/src/expr/node.h b/src/expr/node.h
index 7003aae87..e6a163a8b 100644
--- a/src/expr/node.h
+++ b/src/expr/node.h
@@ -182,7 +182,7 @@ class NodeTemplate {
friend class expr::NodeValue;
friend class expr::pickle::PicklerPrivate;
- friend Node expr::exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
+ friend Node expr::exportInternal(TNode n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap, uint32_t flags);
/** A convenient null-valued encapsulated pointer */
static NodeTemplate s_null;
@@ -1094,7 +1094,7 @@ NodeTemplate<ref_count>& NodeTemplate<ref_count>::
operator=(const NodeTemplate& e) {
Assert(d_nv != NULL, "Expecting a non-NULL expression value!");
Assert(e.d_nv != NULL, "Expecting a non-NULL expression value on RHS!");
- if(EXPECT_TRUE( d_nv != e.d_nv )) {
+ if(__builtin_expect( ( d_nv != e.d_nv ), true )) {
if(ref_count) {
// shouldn't ever fail
Assert(d_nv->d_rc > 0,
@@ -1118,7 +1118,7 @@ NodeTemplate<ref_count>& NodeTemplate<ref_count>::
operator=(const NodeTemplate<!ref_count>& e) {
Assert(d_nv != NULL, "Expecting a non-NULL expression value!");
Assert(e.d_nv != NULL, "Expecting a non-NULL expression value on RHS!");
- if(EXPECT_TRUE( d_nv != e.d_nv )) {
+ if(__builtin_expect( ( d_nv != e.d_nv ), true )) {
if(ref_count) {
// shouldn't ever fail
Assert(d_nv->d_rc > 0, "Node reference count would be negative");
@@ -1337,7 +1337,11 @@ NodeTemplate<ref_count>::substitute(TNode node, TNode replacement,
NodeBuilder<> nb(getKind());
if(getMetaKind() == kind::metakind::PARAMETERIZED) {
// push the operator
- nb << getOperator();
+ if(getOperator() == node) {
+ nb << replacement;
+ } else {
+ nb << getOperator().substitute(node, replacement, cache);
+ }
}
for(const_iterator i = begin(),
iend = end();
diff --git a/src/expr/node_builder.h b/src/expr/node_builder.h
index 773828ccb..64080c275 100644
--- a/src/expr/node_builder.h
+++ b/src/expr/node_builder.h
@@ -228,7 +228,7 @@ class NodeBuilder {
* Internally, this state is represented by d_nv pointing to NULL.
*/
inline bool isUsed() const {
- return EXPECT_FALSE( d_nv == NULL );
+ return __builtin_expect( ( d_nv == NULL ), false );
}
/**
@@ -259,7 +259,7 @@ class NodeBuilder {
* heap-allocated by this class).
*/
inline bool nvIsAllocated() const {
- return EXPECT_FALSE( d_nv != &d_inlineNv ) && EXPECT_TRUE( d_nv != NULL );
+ return __builtin_expect( ( d_nv != &d_inlineNv ), false ) && __builtin_expect(( d_nv != NULL ), true );
}
/**
@@ -267,7 +267,7 @@ class NodeBuilder {
* first.
*/
inline bool nvNeedsToBeAllocated() const {
- return EXPECT_FALSE( d_nv->d_nchildren == d_nvMaxChildren );
+ return __builtin_expect( ( d_nv->d_nchildren == d_nvMaxChildren ), false );
}
/**
@@ -279,7 +279,7 @@ class NodeBuilder {
inline void realloc() {
size_t newSize = 2 * size_t(d_nvMaxChildren);
size_t hardLimit = (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN) - 1;
- realloc(EXPECT_FALSE( newSize > hardLimit ) ? hardLimit : newSize);
+ realloc(__builtin_expect( ( newSize > hardLimit ), false ) ? hardLimit : newSize);
}
/**
@@ -297,7 +297,7 @@ class NodeBuilder {
* double-decremented on destruction/clear. Otherwise, do nothing.
*/
inline void allocateNvIfNecessaryForAppend() {
- if(EXPECT_FALSE( nvNeedsToBeAllocated() )) {
+ if(__builtin_expect( ( nvNeedsToBeAllocated() ), false )) {
realloc();
}
}
@@ -331,8 +331,8 @@ class NodeBuilder {
* @throws bad_alloc if the reallocation fails
*/
void crop() {
- if(EXPECT_FALSE( nvIsAllocated() ) &&
- EXPECT_TRUE( d_nvMaxChildren > d_nv->d_nchildren )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false ) &&
+ __builtin_expect( ( d_nvMaxChildren > d_nv->d_nchildren ), true )) {
// Ensure d_nv is not modified on allocation failure
expr::NodeValue* newBlock = (expr::NodeValue*)
std::realloc(d_nv,
@@ -419,9 +419,9 @@ public:
}
inline ~NodeBuilder() {
- if(EXPECT_FALSE( nvIsAllocated() )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false )) {
dealloc();
- } else if(EXPECT_FALSE( !isUsed() )) {
+ } else if(__builtin_expect( ( !isUsed() ), false )) {
decrRefCounts();
}
}
@@ -578,7 +578,7 @@ public:
// NodeBuilder construction or at the last clear()), but we do
// now. That means we appended a Kind with operator<<(Kind),
// which now (lazily) we'll collapse.
- if(EXPECT_FALSE( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND )) {
+ if(__builtin_expect( ( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND ), false )) {
Node n2 = operator Node();
clear();
append(n2);
@@ -600,7 +600,7 @@ public:
// NodeBuilder construction or at the last clear()), but we do
// now. That means we appended a Kind with operator<<(Kind),
// which now (lazily) we'll collapse.
- if(EXPECT_FALSE( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND )) {
+ if(__builtin_expect( ( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND ), false )) {
Node n2 = operator Node();
clear();
append(n2);
@@ -619,7 +619,7 @@ public:
// NodeBuilder construction or at the last clear()), but we do
// now. That means we appended a Kind with operator<<(Kind),
// which now (lazily) we'll collapse.
- if(EXPECT_FALSE( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND )) {
+ if(__builtin_expect( ( d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND ), false )) {
Node n2 = operator Node();
clear();
append(n2);
@@ -660,6 +660,9 @@ public:
Assert(!isUsed(), "NodeBuilder is one-shot only; "
"attempt to access it after conversion");
Assert(!n.isNull(), "Cannot use NULL Node as a child of a Node");
+ if(n.getKind() == kind::BUILTIN) {
+ return *this << NodeManager::operatorToKind(n);
+ }
allocateNvIfNecessaryForAppend();
expr::NodeValue* nv = n.d_nv;
nv->inc();
@@ -756,9 +759,9 @@ template <unsigned nchild_thresh>
void NodeBuilder<nchild_thresh>::clear(Kind k) {
Assert(k != kind::NULL_EXPR, "illegal Node-building clear kind");
- if(EXPECT_FALSE( nvIsAllocated() )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false )) {
dealloc();
- } else if(EXPECT_FALSE( !isUsed() )) {
+ } else if(__builtin_expect( ( !isUsed() ), false )) {
decrRefCounts();
} else {
setUnused();
@@ -783,7 +786,7 @@ void NodeBuilder<nchild_thresh>::realloc(size_t toSize) {
"attempt to realloc() a NodeBuilder to size %u (beyond hard limit of %u)",
toSize, (1lu << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN) - 1 );
- if(EXPECT_FALSE( nvIsAllocated() )) {
+ if(__builtin_expect( ( nvIsAllocated() ), false )) {
// Ensure d_nv is not modified on allocation failure
expr::NodeValue* newBlock = (expr::NodeValue*)
std::realloc(d_nv, sizeof(expr::NodeValue) +
@@ -980,7 +983,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() {
#if 0
// if the kind is PARAMETERIZED, check that the operator is correctly-kinded
Assert(kind::metaKindOf(getKind()) != kind::metakind::PARAMETERIZED ||
- kind::operatorKindToKind(getOperator().getKind()) == getKind(),
+ NodeManager::operatorToKind(getOperator()) == getKind(),
"Attempted to construct a parameterized kind `%s' with "
"incorrectly-kinded operator `%s'",
kind::kindToString(getKind()).c_str(),
@@ -992,7 +995,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() {
// NodeManager pool of Nodes. See implementation notes at the top
// of this file.
- if(EXPECT_TRUE( ! nvIsAllocated() )) {
+ if(__builtin_expect( ( ! nvIsAllocated() ), true )) {
/** Case 1. d_nv points to d_inlineNv: it is the backing store
** allocated "inline" in this NodeBuilder. **/
@@ -1165,7 +1168,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() const {
#if 0
// if the kind is PARAMETERIZED, check that the operator is correctly-kinded
Assert(kind::metaKindOf(getKind()) != kind::metakind::PARAMETERIZED ||
- kind::operatorKindToKind(getOperator().getKind()) == getKind(),
+ NodeManager::operatorToKind(getOperator()) == getKind(),
"Attempted to construct a parameterized kind `%s' with "
"incorrectly-kinded operator `%s'",
kind::kindToString(getKind()).c_str(),
@@ -1177,7 +1180,7 @@ expr::NodeValue* NodeBuilder<nchild_thresh>::constructNV() const {
// NodeManager pool of Nodes. See implementation notes at the top
// of this file.
- if(EXPECT_TRUE( ! nvIsAllocated() )) {
+ if(__builtin_expect( ( ! nvIsAllocated() ), true )) {
/** Case 1. d_nv points to d_inlineNv: it is the backing store
** allocated "inline" in this NodeBuilder. **/
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index 0c62d31c5..31f6d75d9 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -75,12 +75,12 @@ typedef expr::Attribute<expr::attr::DatatypeRecordTag, TypeNode> DatatypeRecordA
class NodeManagerListener {
public:
virtual ~NodeManagerListener() { }
- virtual void nmNotifyNewSort(TypeNode tn) { }
+ virtual void nmNotifyNewSort(TypeNode tn, uint32_t flags) { }
virtual void nmNotifyNewSortConstructor(TypeNode tn) { }
- virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort) { }
+ virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort, uint32_t flags) { }
virtual void nmNotifyNewDatatypes(const std::vector<DatatypeType>& datatypes) { }
- virtual void nmNotifyNewVar(TNode n, bool isGlobal) { }
- virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, bool isGlobal) { }
+ virtual void nmNotifyNewVar(TNode n, uint32_t flags) { }
+ virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, uint32_t flags) { }
};/* class NodeManagerListener */
class NodeManager {
@@ -90,8 +90,8 @@ class NodeManager {
friend class expr::TypeChecker;
// friends so they can access mkVar() here, which is private
- friend Expr ExprManager::mkVar(const std::string&, Type, bool isGlobal);
- friend Expr ExprManager::mkVar(Type, bool isGlobal);
+ friend Expr ExprManager::mkVar(const std::string&, Type, uint32_t flags);
+ friend Expr ExprManager::mkVar(Type, uint32_t flags);
// friend so it can access NodeManager's d_listeners and notify clients
friend std::vector<DatatypeType> ExprManager::mkMutualDatatypeTypes(const std::vector<Datatype>&, const std::set<Type>&);
@@ -309,12 +309,12 @@ class NodeManager {
* version of this is private to avoid internal uses of mkVar() from
* within CVC4. Such uses should employ mkSkolem() instead.
*/
- Node mkVar(const std::string& name, const TypeNode& type, bool isGlobal = false);
- Node* mkVarPtr(const std::string& name, const TypeNode& type, bool isGlobal = false);
+ Node mkVar(const std::string& name, const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
+ Node* mkVarPtr(const std::string& name, const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
/** Create a variable with the given type. */
- Node mkVar(const TypeNode& type, bool isGlobal = false);
- Node* mkVarPtr(const TypeNode& type, bool isGlobal = false);
+ Node mkVar(const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
+ Node* mkVarPtr(const TypeNode& type, uint32_t flags = ExprManager::VAR_FLAG_NONE);
public:
@@ -353,6 +353,9 @@ public:
d_listeners.erase(elt);
}
+ /** Get a Kind from an operator expression */
+ static inline Kind operatorToKind(TNode n);
+
// general expression-builders
/** Create a node with one child. */
@@ -680,6 +683,9 @@ public:
/** Get the (singleton) type for strings. */
inline TypeNode stringType();
+ /** Get the (singleton) type for RegExp. */
+ inline TypeNode regexpType();
+
/** Get the bound var list type. */
inline TypeNode boundVarListType();
@@ -775,14 +781,15 @@ public:
inline TypeNode mkTesterType(TypeNode domain);
/** Make a new (anonymous) sort of arity 0. */
- inline TypeNode mkSort();
+ inline TypeNode mkSort(uint32_t flags = ExprManager::SORT_FLAG_NONE);
/** Make a new sort with the given name of arity 0. */
- inline TypeNode mkSort(const std::string& name);
+ inline TypeNode mkSort(const std::string& name, uint32_t flags = ExprManager::SORT_FLAG_NONE);
/** Make a new sort by parameterizing the given sort constructor. */
inline TypeNode mkSort(TypeNode constructor,
- const std::vector<TypeNode>& children);
+ const std::vector<TypeNode>& children,
+ uint32_t flags = ExprManager::SORT_FLAG_NONE);
/** Make a new sort with the given name and arity. */
inline TypeNode mkSortConstructor(const std::string& name, size_t arity);
@@ -1026,6 +1033,11 @@ inline TypeNode NodeManager::stringType() {
return TypeNode(mkTypeConst<TypeConstant>(STRING_TYPE));
}
+/** Get the (singleton) type for regexps. */
+inline TypeNode NodeManager::regexpType() {
+ return TypeNode(mkTypeConst<TypeConstant>(REGEXP_TYPE));
+}
+
/** Get the bound var list type. */
inline TypeNode NodeManager::boundVarListType() {
return TypeNode(mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE));
@@ -1087,7 +1099,6 @@ NodeManager::mkPredicateType(const std::vector<TypeNode>& sorts) {
}
inline TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
- Assert(types.size() >= 1);
std::vector<TypeNode> typeNodes;
for (unsigned i = 0; i < types.size(); ++ i) {
CheckArgument(!types[i].isFunctionLike(), types,
@@ -1218,31 +1229,32 @@ inline bool NodeManager::hasOperator(Kind k) {
}
}
-inline TypeNode NodeManager::mkSort() {
+inline TypeNode NodeManager::mkSort(uint32_t flags) {
NodeBuilder<1> nb(this, kind::SORT_TYPE);
Node sortTag = NodeBuilder<0>(this, kind::SORT_TAG);
nb << sortTag;
TypeNode tn = nb.constructTypeNode();
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewSort(tn);
+ (*i)->nmNotifyNewSort(tn, flags);
}
return tn;
}
-inline TypeNode NodeManager::mkSort(const std::string& name) {
+inline TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
NodeBuilder<1> nb(this, kind::SORT_TYPE);
Node sortTag = NodeBuilder<0>(this, kind::SORT_TAG);
nb << sortTag;
TypeNode tn = nb.constructTypeNode();
setAttribute(tn, expr::VarNameAttr(), name);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewSort(tn);
+ (*i)->nmNotifyNewSort(tn, flags);
}
return tn;
}
inline TypeNode NodeManager::mkSort(TypeNode constructor,
- const std::vector<TypeNode>& children) {
+ const std::vector<TypeNode>& children,
+ uint32_t flags) {
Assert(constructor.getKind() == kind::SORT_TYPE &&
constructor.getNumChildren() == 0,
"expected a sort constructor");
@@ -1260,7 +1272,7 @@ inline TypeNode NodeManager::mkSort(TypeNode constructor,
TypeNode type = nb.constructTypeNode();
setAttribute(type, expr::VarNameAttr(), name);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyInstantiateSortConstructor(constructor, type);
+ (*i)->nmNotifyInstantiateSortConstructor(constructor, type, flags);
}
return type;
}
@@ -1280,6 +1292,10 @@ inline TypeNode NodeManager::mkSortConstructor(const std::string& name,
return type;
}
+inline Kind NodeManager::operatorToKind(TNode n) {
+ return kind::operatorToKind(n.d_nv);
+}
+
inline Node NodeManager::mkNode(Kind kind, TNode child1) {
NodeBuilder<1> nb(this, kind);
nb << child1;
@@ -1367,80 +1383,114 @@ inline Node* NodeManager::mkNodePtr(Kind kind,
// for operators
inline Node NodeManager::mkNode(TNode opNode) {
- NodeBuilder<1> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<1> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode) {
- NodeBuilder<1> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<1> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1) {
- NodeBuilder<2> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1;
+ NodeBuilder<2> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1) {
- NodeBuilder<2> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1;
+ NodeBuilder<2> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2) {
- NodeBuilder<3> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2;
+ NodeBuilder<3> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2) {
- NodeBuilder<3> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2;
+ NodeBuilder<3> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2,
TNode child3) {
- NodeBuilder<4> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3;
+ NodeBuilder<4> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2,
TNode child3) {
- NodeBuilder<4> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3;
+ NodeBuilder<4> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4) {
- NodeBuilder<5> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4;
+ NodeBuilder<5> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4) {
- NodeBuilder<5> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4;
+ NodeBuilder<5> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4;
return nb.constructNodePtr();
}
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4, TNode child5) {
- NodeBuilder<6> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4 << child5;
+ NodeBuilder<6> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4 << child5;
return nb.constructNode();
}
inline Node* NodeManager::mkNodePtr(TNode opNode, TNode child1, TNode child2,
TNode child3, TNode child4, TNode child5) {
- NodeBuilder<6> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode << child1 << child2 << child3 << child4 << child5;
+ NodeBuilder<6> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
+ nb << child1 << child2 << child3 << child4 << child5;
return nb.constructNodePtr();
}
@@ -1449,8 +1499,10 @@ template <bool ref_count>
inline Node NodeManager::mkNode(TNode opNode,
const std::vector<NodeTemplate<ref_count> >&
children) {
- NodeBuilder<> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
nb.append(children);
return nb.constructNode();
}
@@ -1459,8 +1511,10 @@ template <bool ref_count>
inline Node* NodeManager::mkNodePtr(TNode opNode,
const std::vector<NodeTemplate<ref_count> >&
children) {
- NodeBuilder<> nb(this, kind::operatorKindToKind(opNode.getKind()));
- nb << opNode;
+ NodeBuilder<> nb(this, operatorToKind(opNode));
+ if(opNode.getKind() != kind::BUILTIN) {
+ nb << opNode;
+ }
nb.append(children);
return nb.constructNodePtr();
}
@@ -1487,27 +1541,27 @@ inline TypeNode NodeManager::mkTypeNode(Kind kind,
}
-inline Node NodeManager::mkVar(const std::string& name, const TypeNode& type, bool isGlobal) {
+inline Node NodeManager::mkVar(const std::string& name, const TypeNode& type, uint32_t flags) {
Node n = NodeBuilder<0>(this, kind::VARIABLE);
setAttribute(n, TypeAttr(), type);
setAttribute(n, TypeCheckedAttr(), true);
setAttribute(n, expr::VarNameAttr(), name);
- setAttribute(n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(n, isGlobal);
+ (*i)->nmNotifyNewVar(n, flags);
}
return n;
}
inline Node* NodeManager::mkVarPtr(const std::string& name,
- const TypeNode& type, bool isGlobal) {
+ const TypeNode& type, uint32_t flags) {
Node* n = NodeBuilder<0>(this, kind::VARIABLE).constructNodePtr();
setAttribute(*n, TypeAttr(), type);
setAttribute(*n, TypeCheckedAttr(), true);
setAttribute(*n, expr::VarNameAttr(), name);
- setAttribute(*n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(*n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(*n, isGlobal);
+ (*i)->nmNotifyNewVar(*n, flags);
}
return n;
}
@@ -1525,24 +1579,24 @@ inline Node* NodeManager::mkBoundVarPtr(const std::string& name,
return n;
}
-inline Node NodeManager::mkVar(const TypeNode& type, bool isGlobal) {
+inline Node NodeManager::mkVar(const TypeNode& type, uint32_t flags) {
Node n = NodeBuilder<0>(this, kind::VARIABLE);
setAttribute(n, TypeAttr(), type);
setAttribute(n, TypeCheckedAttr(), true);
- setAttribute(n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(n, isGlobal);
+ (*i)->nmNotifyNewVar(n, flags);
}
return n;
}
-inline Node* NodeManager::mkVarPtr(const TypeNode& type, bool isGlobal) {
+inline Node* NodeManager::mkVarPtr(const TypeNode& type, uint32_t flags) {
Node* n = NodeBuilder<0>(this, kind::VARIABLE).constructNodePtr();
setAttribute(*n, TypeAttr(), type);
setAttribute(*n, TypeCheckedAttr(), true);
- setAttribute(*n, expr::GlobalVarAttr(), isGlobal);
+ setAttribute(*n, expr::GlobalVarAttr(), flags & ExprManager::VAR_FLAG_GLOBAL);
for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
- (*i)->nmNotifyNewVar(*n, isGlobal);
+ (*i)->nmNotifyNewVar(*n, flags);
}
return n;
}
diff --git a/src/expr/node_value.h b/src/expr/node_value.h
index 13fdc6a7f..56ac70c1e 100644
--- a/src/expr/node_value.h
+++ b/src/expr/node_value.h
@@ -299,7 +299,7 @@ private:
RefCountGuard(const NodeValue* nv) :
d_nv(const_cast<NodeValue*>(nv)) {
// inc()
- if(EXPECT_TRUE( d_nv->d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_nv->d_rc < MAX_RC ), true )) {
++d_nv->d_rc;
}
}
@@ -309,7 +309,7 @@ private:
// E.g., this can happen when debugging code calls the print
// routines below. As RefCountGuards are scoped on the stack,
// this should be fine---but not in multithreaded contexts!
- if(EXPECT_TRUE( d_nv->d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_nv->d_rc < MAX_RC ), true )) {
--d_nv->d_rc;
}
}
@@ -400,16 +400,16 @@ inline void NodeValue::inc() {
"NodeValue is currently being deleted "
"and increment is being called on it. Don't Do That!");
// FIXME multithreading
- if(EXPECT_TRUE( d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_rc < MAX_RC ), true )) {
++d_rc;
}
}
inline void NodeValue::dec() {
// FIXME multithreading
- if(EXPECT_TRUE( d_rc < MAX_RC )) {
+ if(__builtin_expect( ( d_rc < MAX_RC ), true )) {
--d_rc;
- if(EXPECT_FALSE( d_rc == 0 )) {
+ if(__builtin_expect( ( d_rc == 0 ), false )) {
Assert(NodeManager::currentNM() != NULL,
"No current NodeManager on destruction of NodeValue: "
"maybe a public CVC4 interface function is missing a NodeManagerScope ?");
diff --git a/src/expr/type.cpp b/src/expr/type.cpp
index 71c25bd50..f3cf992ba 100644
--- a/src/expr/type.cpp
+++ b/src/expr/type.cpp
@@ -317,6 +317,10 @@ bool Type::isSubrange() const {
return d_typeNode->isSubrange();
}
+size_t FunctionType::getArity() const {
+ return d_typeNode->getNumChildren() - 1;
+}
+
vector<Type> FunctionType::getArgTypes() const {
NodeManagerScope nms(d_nodeManager);
vector<Type> args;
diff --git a/src/expr/type.h b/src/expr/type.h
index 5e4e86264..3c772d461 100644
--- a/src/expr/type.h
+++ b/src/expr/type.h
@@ -415,6 +415,9 @@ public:
/** Construct from the base type */
FunctionType(const Type& type = Type()) throw(IllegalArgumentException);
+ /** Get the arity of the function type */
+ size_t getArity() const;
+
/** Get the argument types */
std::vector<Type> getArgTypes() const;
diff --git a/src/expr/type.i b/src/expr/type.i
index e227cca23..6394dda67 100644
--- a/src/expr/type.i
+++ b/src/expr/type.i
@@ -2,7 +2,11 @@
#include "expr/type.h"
%}
+#ifdef SWIGPYTHON
+%rename(doApply) CVC4::TypeHashFunction::operator()(const CVC4::Type&) const;
+#else /* SWIGPYTHON */
%rename(apply) CVC4::TypeHashFunction::operator()(const CVC4::Type&) const;
+#endif /* SWIGPYTHON */
%ignore CVC4::operator<<(std::ostream&, const Type&);
diff --git a/src/expr/type_node.cpp b/src/expr/type_node.cpp
index e654b5d71..2fc380224 100644
--- a/src/expr/type_node.cpp
+++ b/src/expr/type_node.cpp
@@ -123,6 +123,15 @@ bool TypeNode::isSubtypeOf(TypeNode t) const {
}
return true;
}
+ if(isFunction()) {
+ // A function is a subtype of another if the args are the same type, and
+ // the return type is a subtype of the other's. This is enough for now
+ // (and it's necessary for model generation, since a Real-valued function
+ // might return a constant Int and thus the model value is typed differently).
+ return t.isFunction() &&
+ getArgTypes() == t.getArgTypes() &&
+ getRangeType().isSubtypeOf(t.getRangeType());
+ }
if(isPredicateSubtype()) {
return getSubtypeParentType().isSubtypeOf(t);
}
@@ -291,7 +300,7 @@ TypeNode TypeNode::leastCommonTypeNode(TypeNode t0, TypeNode t1){
Assert(!t0.isNull());
Assert(!t1.isNull());
- if(EXPECT_TRUE(t0 == t1)) {
+ if(__builtin_expect( (t0 == t1), true )) {
return t0;
} else { // t0 != t1
if(t0.getKind()== kind::TYPE_CONSTANT) {
diff --git a/src/expr/type_node.h b/src/expr/type_node.h
index 35d630a91..145ca2aba 100644
--- a/src/expr/type_node.h
+++ b/src/expr/type_node.h
@@ -554,6 +554,9 @@ public:
/** Get the constituent types of a symbolic expression type */
std::vector<TypeNode> getSExprTypes() const;
+ /** Is this a regexp type */
+ bool isRegExp() const;
+
/** Is this a bit-vector type */
bool isBitVector() const;
@@ -619,7 +622,7 @@ public:
* If this is \top, i.e. there is no inhabited type that contains both,
* a TypeNode such that isNull() is true is returned.
*
- * For more information see: http://church.cims.nyu.edu/wiki/Cvc4_Type_Lattice
+ * For more information see: http://cvc4.cs.nyu.edu/wiki/Cvc4_Type_Lattice
*/
static TypeNode leastCommonTypeNode(TypeNode t0, TypeNode t1);
@@ -770,7 +773,7 @@ inline TypeNode& TypeNode::operator=(const TypeNode& typeNode) {
Assert(d_nv != NULL, "Expecting a non-NULL expression value!");
Assert(typeNode.d_nv != NULL,
"Expecting a non-NULL expression value on RHS!");
- if(EXPECT_TRUE( d_nv != typeNode.d_nv )) {
+ if(__builtin_expect( ( d_nv != typeNode.d_nv ), true )) {
d_nv->dec();
d_nv = typeNode.d_nv;
d_nv->inc();
@@ -842,6 +845,12 @@ inline bool TypeNode::isString() const {
getConst<TypeConstant>() == STRING_TYPE;
}
+/** Is this a regexp type */
+inline bool TypeNode::isRegExp() const {
+ return getKind() == kind::TYPE_CONSTANT &&
+ getConst<TypeConstant>() == REGEXP_TYPE;
+}
+
inline bool TypeNode::isArray() const {
return getKind() == kind::ARRAY_TYPE;
}
diff --git a/src/include/cvc4_private_library.h b/src/include/cvc4_private_library.h
index b04160a81..f7fd1b607 100644
--- a/src/include/cvc4_private_library.h
+++ b/src/include/cvc4_private_library.h
@@ -19,7 +19,7 @@
#ifndef __CVC4_PRIVATE_LIBRARY_H
#define __CVC4_PRIVATE_LIBRARY_H
-#if ! (defined(__BUILDING_CVC4LIB) || defined(__BUILDING_CVC4LIB_UNIT_TEST) || defined(__BUILDING_CVC4PARSERLIB) || defined(__BUILDING_CVC4PARSERLIB_UNIT_TEST) || defined(__BUILDING_CVC4DRIVER))
+#if ! (defined(__BUILDING_CVC4LIB) || defined(__BUILDING_CVC4LIB_UNIT_TEST) || defined(__BUILDING_CVC4PARSERLIB) || defined(__BUILDING_CVC4PARSERLIB_UNIT_TEST) || defined(__BUILDING_CVC4COMPATLIB) || defined(__BUILDING_CVC4DRIVER))
# warning A "private library" CVC4 header was included when not building the library, driver, or private unit test code.
#endif /* ! (__BUILDING_CVC4LIB || __BUILDING_CVC4LIB_UNIT_TEST || __BUILDING_CVC4PARSERLIB || __BUILDING_CVC4PARSERLIB_UNIT_TEST || __BUILDING_CVC4DRIVER) */
diff --git a/src/include/cvc4_public.h b/src/include/cvc4_public.h
index b8c30aeef..b7431ce1c 100644
--- a/src/include/cvc4_public.h
+++ b/src/include/cvc4_public.h
@@ -68,7 +68,4 @@
# define CVC4_WARN_UNUSED_RESULT
#endif /* __GNUC__ */
-#define EXPECT_TRUE(x) __builtin_expect( (x), true )
-#define EXPECT_FALSE(x) __builtin_expect( (x), false )
-
#endif /* __CVC4_PUBLIC_H */
diff --git a/src/lib/clock_gettime.h b/src/lib/clock_gettime.h
index 2d3455aed..43c3395a4 100644
--- a/src/lib/clock_gettime.h
+++ b/src/lib/clock_gettime.h
@@ -30,7 +30,7 @@
/* otherwise, we have to define it */
-#ifdef __WIN32__
+#if defined(__WIN32__) && !defined(__WIN64__)
#ifdef __cplusplus
extern "C" {
@@ -45,12 +45,12 @@ struct timespec {
}/* extern "C" */
#endif /* __cplusplus */
-#else /* ! __WIN32__ */
+#else /* !__WIN32__ || __WIN64__ */
/* get timespec from <time.h> */
#include <time.h>
-#endif /* __WIN32__ */
+#endif /* __WIN32__ && !__WIN64__ */
#ifdef __cplusplus
extern "C" {
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index f1742b549..9ee896107 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -19,14 +19,17 @@
#include "main/main.h"
+#include "smt/options.h"
+
namespace CVC4 {
namespace main {
-CommandExecutor::CommandExecutor(ExprManager &exprMgr, Options &options):
+CommandExecutor::CommandExecutor(ExprManager &exprMgr, Options &options) :
d_exprMgr(exprMgr),
d_smtEngine(SmtEngine(&exprMgr)),
d_options(options),
- d_stats("driver") {
+ d_stats("driver"),
+ d_result() {
}
bool CommandExecutor::doCommand(Command* cmd)
@@ -56,7 +59,7 @@ bool CommandExecutor::doCommand(Command* cmd)
}
}
-bool CommandExecutor::doCommandSingleton(Command *cmd)
+bool CommandExecutor::doCommandSingleton(Command* cmd)
{
bool status = true;
if(d_options[options::verbosity] >= -1) {
@@ -64,14 +67,27 @@ bool CommandExecutor::doCommandSingleton(Command *cmd)
} else {
status = smtEngineInvoke(&d_smtEngine, cmd, NULL);
}
+ Result res;
+ CheckSatCommand* cs = dynamic_cast<CheckSatCommand*>(cmd);
+ if(cs != NULL) {
+ d_result = res = cs->getResult();
+ }
+ QueryCommand* q = dynamic_cast<QueryCommand*>(cmd);
+ if(q != NULL) {
+ d_result = res = q->getResult();
+ }
+ // dump the model if option is set
+ if( status &&
+ d_options[options::produceModels] &&
+ d_options[options::dumpModels] &&
+ ( res.asSatisfiabilityResult() == Result::SAT ||
+ (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) {
+ Command* gm = new GetModelCommand();
+ status = doCommandSingleton(gm);
+ }
return status;
}
-std::string CommandExecutor::getSmtEngineStatus()
-{
- return d_smtEngine.getInfo("status").getValue();
-}
-
bool smtEngineInvoke(SmtEngine* smt, Command* cmd, std::ostream *out)
{
if(out == NULL) {
diff --git a/src/main/command_executor.h b/src/main/command_executor.h
index f1b8d8f2f..cbc71b075 100644
--- a/src/main/command_executor.h
+++ b/src/main/command_executor.h
@@ -34,6 +34,7 @@ protected:
SmtEngine d_smtEngine;
Options& d_options;
StatisticsRegistry d_stats;
+ Result d_result;
public:
CommandExecutor(ExprManager &exprMgr, Options &options);
@@ -47,7 +48,7 @@ public:
*/
bool doCommand(CVC4::Command* cmd);
- virtual std::string getSmtEngineStatus();
+ Result getResult() const { return d_result; }
StatisticsRegistry& getStatisticsRegistry() {
return d_stats;
diff --git a/src/main/command_executor_portfolio.cpp b/src/main/command_executor_portfolio.cpp
index 63f689d48..e58df5699 100644
--- a/src/main/command_executor_portfolio.cpp
+++ b/src/main/command_executor_portfolio.cpp
@@ -184,7 +184,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
// command
if(dynamic_cast<CheckSatCommand*>(cmd) != NULL ||
- dynamic_cast<QueryCommand*>(cmd) != NULL) {
+ dynamic_cast<QueryCommand*>(cmd) != NULL) {
mode = 1;
} else if(dynamic_cast<GetValueCommand*>(cmd) != NULL ||
dynamic_cast<GetAssignmentCommand*>(cmd) != NULL ||
@@ -198,6 +198,10 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
mode = 2;
}
+ Debug("portfolio::outputmode") << "Mode is " << mode
+ << "lastWinner is " << d_lastWinner
+ << "d_seq is " << d_seq << std::endl;
+
if(mode == 0) {
d_seq->addCommand(cmd->clone());
Command* cmdExported =
@@ -214,7 +218,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
// We currently don't support changing number of threads for each
// command, but things have been architected in a way so that this
- // can be acheived with not a lot of work
+ // can be achieved without a lot of work.
Command *seqs[d_numThreads];
if(d_lastWinner == 0)
@@ -238,7 +242,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
int(i) == d_lastWinner ?
cmd->exportTo(d_exprMgrs[i], *(d_vmaps[i])) :
d_seq->exportTo(d_exprMgrs[i], *(d_vmaps[i]) );
- }catch(ExportUnsupportedException& e){
+ } catch(ExportUnsupportedException& e) {
if(d_options[options::fallbackSequential]) {
Notice() << "Unsupported theory encountered, switching to sequential mode.";
return CommandExecutor::doCommandSingleton(cmd);
@@ -292,11 +296,11 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
runPortfolio(d_numThreads, smFn, fns,
d_options[options::waitToJoin]);
- d_seq = NULL;
delete d_seq;
d_seq = new CommandSequence();
d_lastWinner = portfolioReturn.first;
+ d_result = d_smts[d_lastWinner]->getStatusOfLastCommand();
if(d_ostringstreams.size() != 0) {
assert(d_numThreads == d_options[options::threads]);
@@ -340,11 +344,6 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
}/* CommandExecutorPortfolio::doCommandSingleton() */
-std::string CommandExecutorPortfolio::getSmtEngineStatus()
-{
- return d_smts[d_lastWinner]->getInfo("status").getValue();
-}
-
void CommandExecutorPortfolio::flushStatistics(std::ostream& out) const {
assert(d_numThreads == d_exprMgrs.size() && d_exprMgrs.size() == d_smts.size());
for(size_t i = 0; i < d_numThreads; ++i) {
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index f57d4f2d7..d42f389c1 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -123,7 +123,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
exit(0);
}
- segvNoSpin = opts[options::segvNoSpin];
+ segvSpin = opts[options::segvSpin];
// If in competition mode, set output stream option to flush immediately
#ifdef CVC4_COMPETITION_MODE
@@ -297,13 +297,13 @@ int runCvc4(int argc, char* argv[], Options& opts) {
opts.set(options::replayStream, NULL);
}
- string result = "unknown";
+ Result result;
if(status) {
- result = pExecutor->getSmtEngineStatus();
+ result = pExecutor->getResult();
- if(result == "sat") {
+ if(result.asSatisfiabilityResult() == Result::SAT) {
returnValue = 10;
- } else if(result == "unsat") {
+ } else if(result.asSatisfiabilityResult() == Result::UNSAT) {
returnValue = 20;
} else {
returnValue = 0;
diff --git a/src/main/interactive_shell.cpp b/src/main/interactive_shell.cpp
index 3376e9d0b..a8099ca30 100644
--- a/src/main/interactive_shell.cpp
+++ b/src/main/interactive_shell.cpp
@@ -33,6 +33,7 @@
#include "parser/parser_builder.h"
#include "options/options.h"
#include "util/language.h"
+#include "util/output.h"
#include <string.h>
#include <cassert>
@@ -313,7 +314,11 @@ restart:
line += "\n";
goto restart;
} catch(ParserException& pe) {
- d_out << pe << endl;
+ if(d_options[options::outputLanguage] == output::LANG_SMTLIB_V2) {
+ d_out << "(error \"" << pe << "\")" << endl;
+ } else {
+ d_out << pe << endl;
+ }
// We can't really clear out the sequence and abort the current line,
// because the parse error might be for the second command on the
// line. The first ones haven't yet been executed by the SmtEngine,
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 7b61b48aa..a4c4b9c0a 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -37,10 +37,12 @@
#include "util/output.h"
#include "util/result.h"
#include "util/statistics.h"
+#include "util/language.h"
using namespace std;
using namespace CVC4;
using namespace CVC4::main;
+using namespace CVC4::language;
/**
* CVC4's main() routine is just an exception-safe wrapper around CVC4.
@@ -64,7 +66,11 @@ int main(int argc, char* argv[]) {
#ifdef CVC4_COMPETITION_MODE
*opts[options::out] << "unknown" << endl;
#endif
- *opts[options::err] << "CVC4 Error:" << endl << e << endl;
+ if(opts[options::outputLanguage] == output::LANG_SMTLIB_V2) {
+ *opts[options::err] << "(error \"" << e << "\")" << endl;
+ } else {
+ *opts[options::err] << "CVC4 Error:" << endl << e << endl;
+ }
if(opts[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(*opts[options::err]);
diff --git a/src/main/main.h b/src/main/main.h
index 0180c34d2..154919aa9 100644
--- a/src/main/main.h
+++ b/src/main/main.h
@@ -51,7 +51,7 @@ extern CVC4::TimerStat* pTotalTime;
* Useful for nightly regressions, noninteractive performance runs
* etc. See util.cpp.
*/
-extern bool segvNoSpin;
+extern bool segvSpin;
/** A pointer to the options in play */
extern CVC4_THREADLOCAL(Options*) pOptions;
diff --git a/src/main/options b/src/main/options
index 14a7a9f3f..ba36e43ab 100644
--- a/src/main/options
+++ b/src/main/options
@@ -38,6 +38,10 @@ option fallbackSequential --fallback-sequential bool :default false
option incrementalParallel --incremental-parallel bool :default false :link --incremental
Use parallel solver even in incremental mode (may print 'unknown's at times)
+option segvSpin --segv-spin bool :default false
+ spin on segfault/other crash waiting for gdb
+undocumented-alias --segv-nospin = --no-segv-spin
+
expert-option waitToJoin --wait-to-join bool :default true
wait for other threads to join before quitting
diff --git a/src/main/portfolio.cpp b/src/main/portfolio.cpp
index 263458247..cf8bba1ba 100644
--- a/src/main/portfolio.cpp
+++ b/src/main/portfolio.cpp
@@ -38,6 +38,8 @@ int global_winner;
template<typename S>
void runThread(int thread_id, boost::function<S()> threadFn, S& returnValue)
{
+ /* Uncommment line to delay first thread, useful to unearth errors/debug */
+ // if(thread_id == 0) { sleep(1); }
returnValue = threadFn();
if( mutex_done.try_lock() ) {
diff --git a/src/main/portfolio_util.h b/src/main/portfolio_util.h
index 6f6e2f03b..d22ca07d9 100644
--- a/src/main/portfolio_util.h
+++ b/src/main/portfolio_util.h
@@ -21,6 +21,7 @@
#include "util/channel.h"
#include "util/lemma_input_channel.h"
#include "util/lemma_output_channel.h"
+#include "util/output.h"
#include "main/options.h"
namespace CVC4 {
diff --git a/src/main/util.cpp b/src/main/util.cpp
index 5bd0c9bd4..14ee82613 100644
--- a/src/main/util.cpp
+++ b/src/main/util.cpp
@@ -54,7 +54,7 @@ namespace main {
* Useful for nightly regressions, noninteractive performance runs
* etc.
*/
-bool segvNoSpin = false;
+bool segvSpin = false;
#ifndef __WIN32__
@@ -98,8 +98,7 @@ void segv_handler(int sig, siginfo_t* info, void* c) {
cerr << "Looks like a NULL pointer was dereferenced." << endl;
}
- if(segvNoSpin) {
- fprintf(stderr, "No-spin requested, aborting...\n");
+ if(!segvSpin) {
if((*pOptions)[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(cerr);
@@ -133,8 +132,7 @@ void segv_handler(int sig, siginfo_t* info, void* c) {
void ill_handler(int sig, siginfo_t* info, void*) {
#ifdef CVC4_DEBUG
fprintf(stderr, "CVC4 executed an illegal instruction in DEBUG mode.\n");
- if(segvNoSpin) {
- fprintf(stderr, "No-spin requested, aborting...\n");
+ if(!segvSpin) {
if((*pOptions)[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(cerr);
@@ -174,8 +172,7 @@ void cvc4unexpected() {
fprintf(stderr, "The exception is:\n%s\n\n",
static_cast<const char*>(CVC4::s_debugLastException));
}
- if(segvNoSpin) {
- fprintf(stderr, "No-spin requested.\n");
+ if(!segvSpin) {
if((*pOptions)[options::statistics] && pExecutor != NULL) {
pTotalTime->stop();
pExecutor->flushStatistics(cerr);
diff --git a/src/options/Makefile.am b/src/options/Makefile.am
index 21988df56..5b0894680 100644
--- a/src/options/Makefile.am
+++ b/src/options/Makefile.am
@@ -23,6 +23,8 @@ OPTIONS_FILES_SRCS = \
../theory/quantifiers/options.h \
../theory/rewriterules/options.cpp \
../theory/rewriterules/options.h \
+ ../theory/strings/options.cpp \
+ ../theory/strings/options.h \
../prop/options.cpp \
../prop/options.h \
../proof/options.cpp \
@@ -36,7 +38,9 @@ OPTIONS_FILES_SRCS = \
../main/options.cpp \
../main/options.h \
../parser/options.cpp \
- ../parser/options.h
+ ../parser/options.h \
+ ../theory/idl/options.cpp \
+ ../theory/idl/options.h
OPTIONS_FILES = \
$(patsubst %.cpp,%,$(filter %.cpp,$(OPTIONS_FILES_SRCS)))
@@ -80,6 +84,8 @@ nodist_liboptions_la_SOURCES = \
../theory/quantifiers/options.h \
../theory/rewriterules/options.cpp \
../theory/rewriterules/options.h \
+ ../theory/strings/options.cpp \
+ ../theory/strings/options.h \
../prop/options.cpp \
../prop/options.h \
../proof/options.cpp \
@@ -93,7 +99,9 @@ nodist_liboptions_la_SOURCES = \
../main/options.cpp \
../main/options.h \
../parser/options.cpp \
- ../parser/options.h
+ ../parser/options.h \
+ ../theory/idl/options.cpp \
+ ../theory/idl/options.h
BUILT_SOURCES = \
exprs-builts \
diff --git a/src/options/base_options b/src/options/base_options
index 71754cca5..a6f24c7f3 100644
--- a/src/options/base_options
+++ b/src/options/base_options
@@ -103,7 +103,7 @@ common-option - -v --verbose void :handler CVC4::options::increaseVerbosity
common-option - -q --quiet void :handler CVC4::options::decreaseVerbosity
decrease verbosity (may be repeated)
-common-option statistics statistics --stats bool
+common-option statistics statistics --stats bool :predicate CVC4::smt::statsEnabledBuild :predicate-include "smt/options_handlers.h"
give statistics on exit
undocumented-alias --statistics = --stats
undocumented-alias --no-statistics = --no-stats
@@ -114,9 +114,6 @@ option parseOnly parse-only --parse-only bool :read-write
option preprocessOnly preprocess-only --preprocess-only bool
exit after preprocessing input
-option segvNoSpin --segv-nospin bool
- don't spin on segfault waiting for gdb
-
option - trace -t --trace=TAG argument :handler CVC4::options::addTraceTag
trace something (e.g. -t pushpop), can repeat
option - debug -d --debug=TAG argument :handler CVC4::options::addDebugTag
diff --git a/src/options/mkoptions b/src/options/mkoptions
index fa6c4c260..d856c7293 100755
--- a/src/options/mkoptions
+++ b/src/options/mkoptions
@@ -73,7 +73,9 @@ options_cpp_template="$1"; shift
all_modules_defaults=
all_modules_short_options=
all_modules_long_options=
+all_modules_smt_options=
all_modules_option_handlers=
+all_modules_get_options=
smt_getoption_handlers=
smt_setoption_handlers=
include_all_option_headers=
@@ -665,14 +667,64 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
fi
if [ -n "$smtname" ]; then
+ all_modules_smt_options="${all_modules_smt_options:+$all_modules_smt_options,}
+#line $lineno \"$kf\"
+ \"$smtname\""
if [ "$internal" != - ]; then
- smt_getoption_handlers="${smt_getoption_handlers}
+ case "$type" in
+ bool)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(SExpr::Keyword(d_holder->$internal ? \"true\" : \"false\")); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ return SExprKeyword(options::$internal() ? \"true\" : \"false\");
+ }";;
+ int|unsigned|int*_t|uint*_t|unsigned\ long|long|CVC4::Integer)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(d_holder->$internal); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ return SExpr(Integer(options::$internal()));
+ }";;
+ float|double)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(Rational::fromDouble(d_holder->$internal)); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ stringstream ss; ss << std::fixed << options::$internal();
+ return SExpr(Rational::fromDecimal(ss.str()));
+ }";;
+ CVC4::Rational)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(d_holder->$internal); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
+#line $lineno \"$kf\"
+ if(key == \"$smtname\") {
+#line $lineno \"$kf\"
+ return SExpr(options::$internal());
+ }";;
+ *)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::stringstream ss; ss << d_holder->$internal; std::vector<SExpr> v; v.push_back(\"$smtname\"); v.push_back(ss.str()); opts.push_back(v); }"
+ smt_getoption_handlers="${smt_getoption_handlers}
#line $lineno \"$kf\"
if(key == \"$smtname\") {
#line $lineno \"$kf\"
stringstream ss; ss << options::$internal();
return SExpr(ss.str());
- }"
+ }";;
+ esac
fi
if [ "$type" = bool ]; then
@@ -731,6 +783,36 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
return;
}"
fi
+ elif [ -n "$long_option" -o "$long_option_alternate" ] && [ "$internal" != - ]; then
+ case "$type" in
+ bool)
+ getoption_name="$long_option"
+ inv=
+ # case where we have a --disable but no corresponding --enable
+ if [ -z "$getoption_name" ]; then
+ getoption_name="$long_option_alternate"
+ inv='!'
+ fi
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$getoption_name\"); v.push_back(SExpr::Keyword((${inv}d_holder->$internal) ? \"true\" : \"false\")); opts.push_back(v); }";;
+ int|unsigned|int*_t|uint*_t|unsigned\ long|long|CVC4::Integer)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(d_holder->$internal); opts.push_back(v); }";;
+ float|double)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(Rational::fromDouble(d_holder->$internal)); opts.push_back(v); }";;
+ CVC4::Rational)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(d_holder->$internal); opts.push_back(v); }";;
+ *)
+ all_modules_get_options="${all_modules_get_options:+$all_modules_get_options
+#line $lineno \"$kf\"
+ }{ std::stringstream ss; ss << d_holder->$internal; std::vector<SExpr> v; v.push_back(\"$long_option\"); v.push_back(ss.str()); opts.push_back(v); }";;
+ esac
fi
if [ "$type" = bool ]; then
@@ -1446,7 +1528,9 @@ for var in \
all_modules_defaults \
all_modules_short_options \
all_modules_long_options \
+ all_modules_smt_options \
all_modules_option_handlers \
+ all_modules_get_options \
include_all_option_headers \
all_modules_contributions \
all_custom_handlers \
diff --git a/src/options/options.h b/src/options/options.h
index 2be0e7b51..eaafade93 100644
--- a/src/options/options.h
+++ b/src/options/options.h
@@ -27,6 +27,7 @@
#include "options/option_exception.h"
#include "util/language.h"
#include "util/tls.h"
+#include "util/sexpr.h"
namespace CVC4 {
@@ -118,12 +119,33 @@ public:
static void printLanguageHelp(std::ostream& out);
/**
+ * Look up long command-line option names that bear some similarity to
+ * the given name. Don't include the initial "--". This might be
+ * useful in case of typos. Can return an empty vector if there are
+ * no suggestions.
+ */
+ static std::vector<std::string> suggestCommandLineOptions(const std::string& optionName) throw();
+
+ /**
+ * Look up SMT option names that bear some similarity to
+ * the given name. Don't include the initial ":". This might be
+ * useful in case of typos. Can return an empty vector if there are
+ * no suggestions.
+ */
+ static std::vector<std::string> suggestSmtOptions(const std::string& optionName) throw();
+
+ /**
* Initialize the options based on the given command-line arguments.
* The return value is what's left of the command line (that is, the
* non-option arguments).
*/
std::vector<std::string> parseOptions(int argc, char* argv[]) throw(OptionException);
+ /**
+ * Get the setting for all options.
+ */
+ SExpr getOptions() const throw();
+
};/* class Options */
}/* CVC4 namespace */
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index 81ffe1b27..d97d11364 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -14,6 +14,26 @@
** Contains code for handling command-line options
**/
+#if !defined(_BSD_SOURCE) && defined(__MINGW32__) && !defined(__MINGW64__)
+// force use of optreset; mingw32 croaks on argv-switching otherwise
+# include "cvc4autoconfig.h"
+# define _BSD_SOURCE
+# undef HAVE_DECL_OPTRESET
+# define HAVE_DECL_OPTRESET 1
+# define CVC4_IS_NOT_REALLY_BSD
+#endif /* !_BSD_SOURCE && __MINGW32__ && !__MINGW64__ */
+
+#ifdef __MINGW64__
+extern int optreset;
+#endif /* __MINGW64__ */
+
+#include <getopt.h>
+
+// clean up
+#ifdef CVC4_IS_NOT_REALLY_BSD
+# undef _BSD_SOURCE
+#endif /* CVC4_IS_NOT_REALLY_BSD */
+
#include <cstdio>
#include <cstdlib>
#include <new>
@@ -25,8 +45,6 @@
#include <stdint.h>
#include <time.h>
-#include <getopt.h>
-
#include "expr/expr.h"
#include "util/configuration.h"
#include "util/exception.h"
@@ -35,7 +53,7 @@
${include_all_option_headers}
-#line 39 "${template}"
+#line 57 "${template}"
#include "util/output.h"
#include "options/options_holder.h"
@@ -44,7 +62,7 @@ ${include_all_option_headers}
${option_handler_includes}
-#line 48 "${template}"
+#line 66 "${template}"
using namespace CVC4;
using namespace CVC4::options;
@@ -181,7 +199,7 @@ void runBoolPredicates(T, std::string option, bool b, SmtEngine* smt) {
${all_custom_handlers}
-#line 185 "${template}"
+#line 203 "${template}"
#ifdef CVC4_DEBUG
# define USE_EARLY_TYPE_CHECKING_BY_DEFAULT true
@@ -211,18 +229,18 @@ options::OptionsHolder::OptionsHolder() : ${all_modules_defaults}
{
}
-#line 215 "${template}"
+#line 233 "${template}"
static const std::string mostCommonOptionsDescription = "\
Most commonly-used CVC4 options:${common_documentation}";
-#line 220 "${template}"
+#line 238 "${template}"
static const std::string optionsDescription = mostCommonOptionsDescription + "\n\
\n\
Additional CVC4 options:${remaining_documentation}";
-#line 226 "${template}"
+#line 244 "${template}"
static const std::string optionsFootnote = "\n\
[*] Each of these options has a --no-OPTIONNAME variant, which reverses the\n\
@@ -293,7 +311,7 @@ static struct option cmdlineOptions[] = {${all_modules_long_options}
{ NULL, no_argument, NULL, '\0' }
};/* cmdlineOptions */
-#line 297 "${template}"
+#line 315 "${template}"
static void preemptGetopt(int& argc, char**& argv, const char* opt) {
const size_t maxoptlen = 128;
@@ -352,6 +370,8 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
const char *progName = main_argv[0];
SmtEngine* const smt = NULL;
+ Debug("options") << "main_argv == " << main_argv << std::endl;
+
// Reset getopt(), in the case of multiple calls to parseOptions().
// This can be = 1 in newer GNU getopt, but older (< 2007) require = 0.
optind = 0;
@@ -443,10 +463,33 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
} while(main_optind < argc && main_argv[main_optind][0] != '-');
continue;
}
+ Debug("options") << "[ before, optind == " << optind << " ]" << std::endl;
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ if(optreset == 1 && optind > 1) {
+ // on mingw, optreset will reset the optind, so we have to
+ // manually advance argc, argv
+ main_argv[optind - 1] = main_argv[0];
+ argv = main_argv += optind - 1;
+ argc -= optind - 1;
+ old_optind = optind = main_optind = 1;
+ if(argc > 0) {
+ Debug("options") << "looking at : " << argv[0] << std::endl;
+ }
+ /*c = getopt_long(argc, main_argv,
+ "+:${all_modules_short_options}",
+ cmdlineOptions, NULL);
+ Debug("options") << "pre-emptory c is " << c << " (" << char(c) << ")" << std::endl;
+ Debug("options") << "optind was reset to " << optind << std::endl;
+ optind = main_optind;
+ Debug("options") << "I restored optind to " << optind << std::endl;*/
+ }
+#endif /* __MINGW32__ || __MINGW64__ */
+ Debug("options") << "[ argc == " << argc << ", main_argv == " << main_argv << " ]" << std::endl;
c = getopt_long(argc, main_argv,
"+:${all_modules_short_options}",
cmdlineOptions, NULL);
main_optind = optind;
+ Debug("options") << "[ got " << int(c) << " (" << char(c) << ") ]" << std::endl;
Debug("options") << "[ next option will be at pos: " << optind << " ]" << std::endl;
if(c == -1) {
Debug("options") << "done with option parsing" << std::endl;
@@ -461,7 +504,7 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
switch(c) {
${all_modules_option_handlers}
-#line 465 "${template}"
+#line 508 "${template}"
case ':':
// This can be a long or short option, and the way to get at the
@@ -518,6 +561,48 @@ ${all_modules_option_handlers}
return nonOptions;
}
+std::vector<std::string> Options::suggestCommandLineOptions(const std::string& optionName) throw() {
+ std::vector<std::string> suggestions;
+
+ const char* opt;
+ for(size_t i = 0; (opt = cmdlineOptions[i].name) != NULL; ++i) {
+ if(std::strstr(opt, optionName.c_str()) != NULL) {
+ suggestions.push_back(opt);
+ }
+ }
+
+ return suggestions;
+}
+
+static const char* smtOptions[] = {
+ ${all_modules_smt_options},
+#line 580 "${template}"
+ NULL
+};/* smtOptions[] */
+
+std::vector<std::string> Options::suggestSmtOptions(const std::string& optionName) throw() {
+ std::vector<std::string> suggestions;
+
+ const char* opt;
+ for(size_t i = 0; (opt = smtOptions[i]) != NULL; ++i) {
+ if(std::strstr(opt, optionName.c_str()) != NULL) {
+ suggestions.push_back(opt);
+ }
+ }
+
+ return suggestions;
+}
+
+SExpr Options::getOptions() const throw() {
+ std::vector<SExpr> opts;
+
+ ${all_modules_get_options}
+
+#line 602 "${template}"
+
+ return SExpr(opts);
+}
+
#undef USE_EARLY_TYPE_CHECKING_BY_DEFAULT
#undef DO_SEMANTIC_CHECKS_BY_DEFAULT
diff --git a/src/parser/antlr_input.cpp b/src/parser/antlr_input.cpp
index cd622b8a6..d498d3c54 100644
--- a/src/parser/antlr_input.cpp
+++ b/src/parser/antlr_input.cpp
@@ -46,9 +46,10 @@ namespace parser {
AntlrInputStream::AntlrInputStream(std::string name,
pANTLR3_INPUT_STREAM input,
bool fileIsTemporary) :
- InputStream(name,fileIsTemporary),
+ InputStream(name, fileIsTemporary),
d_input(input) {
assert( input != NULL );
+ input->fileName = input->strFactory->newStr8(input->strFactory, (pANTLR3_UINT8)name.c_str());
}
AntlrInputStream::~AntlrInputStream() {
@@ -286,16 +287,18 @@ void AntlrInput::warning(const std::string& message) {
void AntlrInput::parseError(const std::string& message, bool eofException)
throw (ParserException) {
Debug("parser") << "Throwing exception: "
- << getInputStream()->getName() << ":"
+ << (const char*)d_lexer->rec->state->tokSource->fileName->chars << ":"
<< d_lexer->getLine(d_lexer) << "."
<< d_lexer->getCharPositionInLine(d_lexer) << ": "
<< message << endl;
if(eofException) {
- throw ParserEndOfFileException(message, getInputStream()->getName(),
+ throw ParserEndOfFileException(message,
+ (const char*)d_lexer->rec->state->tokSource->fileName->chars,
d_lexer->getLine(d_lexer),
d_lexer->getCharPositionInLine(d_lexer));
} else {
- throw ParserException(message, getInputStream()->getName(),
+ throw ParserException(message,
+ (const char*)d_lexer->rec->state->tokSource->fileName->chars,
d_lexer->getLine(d_lexer),
d_lexer->getCharPositionInLine(d_lexer));
}
diff --git a/src/parser/antlr_input.h b/src/parser/antlr_input.h
index 3b7d53be8..8763e8451 100644
--- a/src/parser/antlr_input.h
+++ b/src/parser/antlr_input.h
@@ -14,12 +14,21 @@
** Base for ANTLR parser classes.
**/
+#include <antlr3.h>
+
+// ANTLR3 headers define these in our space :(
+// undef them so that we don't get multiple-definition warnings
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
#include "cvc4parser_private.h"
#ifndef __CVC4__PARSER__ANTLR_INPUT_H
#define __CVC4__PARSER__ANTLR_INPUT_H
-#include <antlr3.h>
#include <iostream>
#include <sstream>
#include <stdexcept>
@@ -34,6 +43,7 @@
#include "util/bitvector.h"
#include "util/integer.h"
#include "util/rational.h"
+#include "util/output.h"
namespace CVC4 {
diff --git a/src/parser/antlr_line_buffered_input.cpp b/src/parser/antlr_line_buffered_input.cpp
index c2f73d988..a59fb3531 100644
--- a/src/parser/antlr_line_buffered_input.cpp
+++ b/src/parser/antlr_line_buffered_input.cpp
@@ -16,6 +16,15 @@
**/
#include <antlr3.h>
+
+// ANTLR3 headers define these in our space :(
+// undef them so that we don't get multiple-definition warnings
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
#include <iostream>
#include <string>
#include <cassert>
diff --git a/src/parser/bounded_token_buffer.cpp b/src/parser/bounded_token_buffer.cpp
index 88a7c6463..112d9b0ed 100644
--- a/src/parser/bounded_token_buffer.cpp
+++ b/src/parser/bounded_token_buffer.cpp
@@ -241,7 +241,7 @@ static pANTLR3_COMMON_TOKEN tokLT(pANTLR3_TOKEN_STREAM ts, ANTLR3_INT32 k) {
}
/* Initialize the buffer on our first call. */
- if( EXPECT_FALSE(buffer->empty == ANTLR3_TRUE) ) {
+ if( __builtin_expect( (buffer->empty == ANTLR3_TRUE), false ) ) {
assert( buffer->tokenBuffer != NULL );
buffer->tokenBuffer[ 0 ] = nextToken(buffer);
buffer->maxIndex = 0;
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 217e7ab97..03d1e7a8a 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -150,6 +150,7 @@ tokens {
MOD_TOK = 'MOD';
INTDIV_TOK = 'DIV';
FLOOR_TOK = 'FLOOR';
+ DISTINCT_TOK = 'DISTINCT';
// Bitvectors
@@ -270,8 +271,7 @@ int getOperatorPrecedence(int type) {
case LEQ_TOK:
case LT_TOK:
case GEQ_TOK:
- case GT_TOK:
- case FLOOR_TOK: return 25;
+ case GT_TOK: return 25;
case EQUAL_TOK:
case DISEQUAL_TOK: return 26;
case NOT_TOK: return 27;
@@ -953,7 +953,7 @@ declareVariables[CVC4::Command*& cmd, CVC4::Type& t, const std::vector<std::stri
} else {
Debug("parser") << " " << *i << " not declared" << std::endl;
if(topLevel) {
- Expr func = PARSER_STATE->mkVar(*i, t, true);
+ Expr func = PARSER_STATE->mkVar(*i, t, ExprManager::VAR_FLAG_GLOBAL);
Command* decl = new DeclareFunctionCommand(*i, func, t);
seq->addCommand(decl);
} else {
@@ -968,13 +968,14 @@ declareVariables[CVC4::Command*& cmd, CVC4::Type& t, const std::vector<std::stri
// like e.g. FORALL(x:INT = 4): [...]
PARSER_STATE->parseError("cannot construct a definition here; maybe you want a LET");
}
- Debug("parser") << "made " << idList.front() << " = " << f << std::endl;
+ assert(!idList.empty());
for(std::vector<std::string>::const_iterator i = idList.begin(),
i_end = idList.end();
i != i_end;
++i) {
+ Debug("parser") << "making " << *i << " : " << t << " = " << f << std::endl;
PARSER_STATE->checkDeclaration(*i, CHECK_UNDECLARED, SYM_VARIABLE);
- Expr func = EXPR_MANAGER->mkVar(*i, t, true);
+ Expr func = EXPR_MANAGER->mkVar(*i, t, ExprManager::VAR_FLAG_GLOBAL | ExprManager::VAR_FLAG_DEFINED);
PARSER_STATE->defineFunction(*i, f);
Command* decl = new DefineFunctionCommand(*i, func, f);
seq->addCommand(decl);
@@ -1162,15 +1163,11 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
}
/* tuple types / old-style function types */
- | LBRACKET type[t,check] { types.push_back(t); }
- ( COMMA type[t,check] { types.push_back(t); } )* RBRACKET
- { if(types.size() == 1) {
- if(types.front().isFunction()) {
- // old style function syntax [ T -> U ]
- PARSER_STATE->parseError("old-style function type syntax not supported anymore; please use the new syntax");
- } else {
- PARSER_STATE->parseError("I'm not sure what you're trying to do here; tuples must have > 1 type");
- }
+ | LBRACKET ( type[t,check] { types.push_back(t); }
+ ( COMMA type[t,check] { types.push_back(t); } )* )? RBRACKET
+ { if(types.size() == 1 && types.front().isFunction()) {
+ // old style function syntax [ T -> U ]
+ PARSER_STATE->parseError("old-style function type syntax not supported anymore; please use the new syntax");
} else {
// tuple type [ T, U, V... ]
t = EXPR_MANAGER->mkTupleType(types);
@@ -1178,13 +1175,17 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
}
/* record types */
- | SQHASH identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); }
- ( COMMA identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); } )* HASHSQ
+ | SQHASH ( identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); }
+ ( COMMA identifier[id,CHECK_NONE,SYM_SORT] COLON type[t,check] { typeIds.push_back(std::make_pair(id, t)); } )* )? HASHSQ
{ t = EXPR_MANAGER->mkRecordType(typeIds); }
/* bitvector types */
| BITVECTOR_TOK LPAREN k=numeral RPAREN
- { t = EXPR_MANAGER->mkBitVectorType(k); }
+ { if(k == 0) {
+ PARSER_STATE->parseError("Illegal bitvector size: 0");
+ }
+ t = EXPR_MANAGER->mkBitVectorType(k);
+ }
/* basic types */
| BOOLEAN_TOK { t = EXPR_MANAGER->booleanType(); }
@@ -1326,7 +1327,7 @@ prefixFormula[CVC4::Expr& f]
{ PARSER_STATE->popScope();
Type t = EXPR_MANAGER->mkFunctionType(types, f.getType());
std::string name = "lambda";
- Expr func = PARSER_STATE->mkAnonymousFunction(name, t);
+ Expr func = PARSER_STATE->mkAnonymousFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
Command* cmd = new DefineFunctionCommand(name, func, terms, f);
PARSER_STATE->preemptCommand(cmd);
f = func;
@@ -1337,7 +1338,7 @@ prefixFormula[CVC4::Expr& f]
boundVarDecl[ids,t] RPAREN COLON formula[f]
{ PARSER_STATE->popScope();
UNSUPPORTED("array literals not supported yet");
- f = EXPR_MANAGER->mkVar(EXPR_MANAGER->mkArrayType(t, f.getType()), true);
+ f = EXPR_MANAGER->mkVar(EXPR_MANAGER->mkArrayType(t, f.getType()), ExprManager::VAR_FLAG_GLOBAL);
}
;
@@ -1368,7 +1369,7 @@ letDecl
: identifier[name,CHECK_NONE,SYM_VARIABLE] EQUAL_TOK formula[e]
{ Debug("parser") << Expr::setlanguage(language::output::LANG_CVC4) << e.getType() << std::endl;
PARSER_STATE->defineVar(name, e);
- Debug("parser") << "LET[" << PARSER_STATE->getDeclarationLevel() << "]: "
+ Debug("parser") << "LET[" << PARSER_STATE->scopeLevel() << "]: "
<< name << std::endl
<< " ==>" << " " << e << std::endl;
}
@@ -1578,7 +1579,7 @@ postfixTerm[CVC4::Expr& f]
std::string id;
Type t;
}
- : bvTerm[f]
+ : ( bvTerm[f]
( /* array select / bitvector extract */
LBRACKET
( formula[f2] { extract = false; }
@@ -1659,6 +1660,13 @@ postfixTerm[CVC4::Expr& f]
}
)
)*
+ | FLOOR_TOK LPAREN formula[f] RPAREN
+ { f = MK_EXPR(CVC4::kind::TO_INTEGER, f); }
+ | DISTINCT_TOK LPAREN
+ formula[f] { args.push_back(f); }
+ ( COMMA formula[f] { args.push_back(f); } )* RPAREN
+ { f = (args.size() == 1) ? MK_CONST(bool(true)) : MK_EXPR(CVC4::kind::DISTINCT, args); }
+ )
( typeAscription[f, t]
{ if(f.getKind() == CVC4::kind::APPLY_CONSTRUCTOR && t.isDatatype()) {
std::vector<CVC4::Expr> v;
@@ -1834,6 +1842,10 @@ simpleTerm[CVC4::Expr& f]
}
}
+ /* empty tuple literal */
+ | LPAREN RPAREN
+ { f = MK_EXPR(kind::TUPLE, std::vector<Expr>()); }
+
/* boolean literals */
| TRUE_TOK { f = MK_CONST(bool(true)); }
| FALSE_TOK { f = MK_CONST(bool(false)); }
@@ -1939,15 +1951,15 @@ datatypeDef[std::vector<CVC4::Datatype>& datatypes]
* below. */
: identifier[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(); }
( LBRACKET identifier[id2,CHECK_UNDECLARED,SYM_SORT] {
- t = PARSER_STATE->mkSort(id2);
+ t = PARSER_STATE->mkSort(id2, ExprManager::SORT_FLAG_PLACEHOLDER);
params.push_back( t );
}
( COMMA identifier[id2,CHECK_UNDECLARED,SYM_SORT] {
- t = PARSER_STATE->mkSort(id2);
+ t = PARSER_STATE->mkSort(id2, ExprManager::SORT_FLAG_PLACEHOLDER);
params.push_back( t ); }
)* RBRACKET
)?
- { datatypes.push_back(Datatype(id,params));
+ { datatypes.push_back(Datatype(id, params));
if(!PARSER_STATE->isUnresolvedType(id)) {
// if not unresolved, must be undeclared
PARSER_STATE->checkDeclaration(id, CHECK_UNDECLARED, SYM_SORT);
diff --git a/src/parser/cvc/Makefile.am b/src/parser/cvc/Makefile.am
index 7c5d48c1c..b7066dd7e 100644
--- a/src/parser/cvc/Makefile.am
+++ b/src/parser/cvc/Makefile.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS = \
-D__BUILDING_CVC4PARSERLIB \
-I@builddir@/../.. -I@srcdir@/../../include -I@srcdir@/../.. $(ANTLR_INCLUDES)
-AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) $(WNO_PARENTHESES) $(WNO_TAUTOLOGICAL_COMPARE) -Wno-unused-function -Wno-unused-variable $(WNO_CONVERSION_NULL)
+AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN) $(WNO_PARENTHESES) $(WNO_TAUTOLOGICAL_COMPARE) -Wno-unused-function -Wno-unused-variable $(WNO_UNINITIALIZED) $(WNO_CONVERSION_NULL)
# Compile generated C files using C++ compiler
CC=$(CXX)
diff --git a/src/parser/options b/src/parser/options
index beae09823..f277b231d 100644
--- a/src/parser/options
+++ b/src/parser/options
@@ -14,4 +14,8 @@ option memoryMap --mmap bool
option semanticChecks /--no-checking bool :default DO_SEMANTIC_CHECKS_BY_DEFAULT :link /--no-type-checking
disable ALL semantic checks, including type checks
+# this is just to support security in the online version
+# (--no-include-file disables filesystem access in TPTP and SMT2 parsers)
+undocumented-option canIncludeFile /--no-include-file bool :default true
+
endmodule
diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp
index 198d1cc31..5d9b6c7ae 100644
--- a/src/parser/parser.cpp
+++ b/src/parser/parser.cpp
@@ -42,11 +42,13 @@ Parser::Parser(ExprManager* exprManager, Input* input, bool strictMode, bool par
d_input(input),
d_symtabAllocated(),
d_symtab(&d_symtabAllocated),
+ d_assertionLevel(0),
d_anonymousFunctionCount(0),
d_done(false),
d_checksEnabled(true),
d_strictMode(strictMode),
- d_parseOnly(parseOnly) {
+ d_parseOnly(parseOnly),
+ d_canIncludeFile(true) {
d_input->setParser(*this);
}
@@ -137,11 +139,10 @@ bool Parser::isPredicate(const std::string& name) {
}
Expr
-Parser::mkVar(const std::string& name, const Type& type,
- bool levelZero) {
- Debug("parser") << "mkVar(" << name << ", " << type << ", " << levelZero << ")" << std::endl;
- Expr expr = d_exprManager->mkVar(name, type, levelZero);
- defineVar(name, expr, levelZero);
+Parser::mkVar(const std::string& name, const Type& type, uint32_t flags) {
+ Debug("parser") << "mkVar(" << name << ", " << type << ")" << std::endl;
+ Expr expr = d_exprManager->mkVar(name, type, flags);
+ defineVar(name, expr, flags & ExprManager::VAR_FLAG_GLOBAL);
return expr;
}
@@ -154,35 +155,31 @@ Parser::mkBoundVar(const std::string& name, const Type& type) {
}
Expr
-Parser::mkFunction(const std::string& name, const Type& type,
- bool levelZero) {
+Parser::mkFunction(const std::string& name, const Type& type, uint32_t flags) {
Debug("parser") << "mkVar(" << name << ", " << type << ")" << std::endl;
- Expr expr = d_exprManager->mkVar(name, type, levelZero);
- defineFunction(name, expr, levelZero);
+ Expr expr = d_exprManager->mkVar(name, type, flags);
+ defineFunction(name, expr, flags & ExprManager::VAR_FLAG_GLOBAL);
return expr;
}
Expr
-Parser::mkAnonymousFunction(const std::string& prefix, const Type& type) {
+Parser::mkAnonymousFunction(const std::string& prefix, const Type& type, uint32_t flags) {
stringstream name;
name << prefix << "_anon_" << ++d_anonymousFunctionCount;
- return mkFunction(name.str(), type);
+ return d_exprManager->mkVar(name.str(), type, flags);
}
std::vector<Expr>
-Parser::mkVars(const std::vector<std::string> names,
- const Type& type,
- bool levelZero) {
+Parser::mkVars(const std::vector<std::string> names, const Type& type, uint32_t flags) {
std::vector<Expr> vars;
for(unsigned i = 0; i < names.size(); ++i) {
- vars.push_back(mkVar(names[i], type, levelZero));
+ vars.push_back(mkVar(names[i], type, flags));
}
return vars;
}
std::vector<Expr>
-Parser::mkBoundVars(const std::vector<std::string> names,
- const Type& type) {
+Parser::mkBoundVars(const std::vector<std::string> names, const Type& type) {
std::vector<Expr> vars;
for(unsigned i = 0; i < names.size(); ++i) {
vars.push_back(mkBoundVar(names[i], type));
@@ -191,16 +188,14 @@ Parser::mkBoundVars(const std::vector<std::string> names,
}
void
-Parser::defineVar(const std::string& name, const Expr& val,
- bool levelZero) {
- Debug("parser") << "defineVar( " << name << " := " << val << " , " << levelZero << ")" << std::endl;;
+Parser::defineVar(const std::string& name, const Expr& val, bool levelZero) {
+ Debug("parser") << "defineVar( " << name << " := " << val << ")" << std::endl;;
d_symtab->bind(name, val, levelZero);
assert( isDeclared(name) );
}
void
-Parser::defineFunction(const std::string& name, const Expr& val,
- bool levelZero) {
+Parser::defineFunction(const std::string& name, const Expr& val, bool levelZero) {
d_symtab->bindDefinedFunction(name, val, levelZero);
assert( isDeclared(name) );
}
@@ -236,9 +231,9 @@ Parser::defineParameterizedType(const std::string& name,
}
SortType
-Parser::mkSort(const std::string& name) {
+Parser::mkSort(const std::string& name, uint32_t flags) {
Debug("parser") << "newSort(" << name << ")" << std::endl;
- Type type = d_exprManager->mkSort(name);
+ Type type = d_exprManager->mkSort(name, flags);
defineType(name, type);
return type;
}
@@ -253,7 +248,7 @@ Parser::mkSortConstructor(const std::string& name, size_t arity) {
}
SortType Parser::mkUnresolvedType(const std::string& name) {
- SortType unresolved = mkSort(name);
+ SortType unresolved = mkSort(name, ExprManager::SORT_FLAG_PLACEHOLDER);
d_unresolved.insert(unresolved);
return unresolved;
}
@@ -357,7 +352,7 @@ Parser::mkMutualDatatypeTypes(const std::vector<Datatype>& datatypes) {
bool Parser::isDeclared(const std::string& name, SymbolType type) {
switch(type) {
case SYM_VARIABLE:
- return d_symtab->isBound(name);
+ return d_reservedSymbols.find(name) != d_reservedSymbols.end() || d_symtab->isBound(name);
case SYM_SORT:
return d_symtab->isBoundType(name);
}
@@ -365,9 +360,15 @@ bool Parser::isDeclared(const std::string& name, SymbolType type) {
return false;
}
+void Parser::reserveSymbolAtAssertionLevel(const std::string& varName) {
+ checkDeclaration(varName, CHECK_UNDECLARED, SYM_VARIABLE);
+ d_reservedSymbols.insert(varName);
+}
+
void Parser::checkDeclaration(const std::string& varName,
DeclarationCheck check,
- SymbolType type)
+ SymbolType type,
+ std::string notes)
throw(ParserException) {
if(!d_checksEnabled) {
return;
@@ -377,14 +378,16 @@ void Parser::checkDeclaration(const std::string& varName,
case CHECK_DECLARED:
if( !isDeclared(varName, type) ) {
parseError("Symbol " + varName + " not declared as a " +
- (type == SYM_VARIABLE ? "variable" : "type"));
+ (type == SYM_VARIABLE ? "variable" : "type") +
+ (notes.size() == 0 ? notes : "\n" + notes));
}
break;
case CHECK_UNDECLARED:
if( isDeclared(varName, type) ) {
parseError("Symbol " + varName + " previously declared as a " +
- (type == SYM_VARIABLE ? "variable" : "type"));
+ (type == SYM_VARIABLE ? "variable" : "type") +
+ (notes.size() == 0 ? notes : "\n" + notes));
}
break;
diff --git a/src/parser/parser.h b/src/parser/parser.h
index 1ca56dc06..b6ba482b7 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -126,6 +126,23 @@ class CVC4_PUBLIC Parser {
*/
SymbolTable* d_symtab;
+ /**
+ * The level of the assertions in the declaration scope. Things declared
+ * after this level are bindings from e.g. a let, a quantifier, or a
+ * lambda.
+ */
+ size_t d_assertionLevel;
+
+ /**
+ * Maintains a list of reserved symbols at the assertion level that might
+ * not occur in our symbol table. This is necessary to e.g. support the
+ * proper behavior of the :named annotation in SMT-LIBv2 when used under
+ * a let or a quantifier, since inside a let/quant body the declaration
+ * scope is that of the let/quant body, but the defined name should be
+ * reserved at the assertion level.
+ */
+ std::set<std::string> d_reservedSymbols;
+
/** How many anonymous functions we've created. */
size_t d_anonymousFunctionCount;
@@ -141,6 +158,12 @@ class CVC4_PUBLIC Parser {
/** Are we only parsing? */
bool d_parseOnly;
+ /**
+ * Can we include files? (Set to false for security purposes in
+ * e.g. the online version.)
+ */
+ bool d_canIncludeFile;
+
/** The set of operators available in the current logic. */
std::set<Kind> d_logicOperators;
@@ -235,6 +258,10 @@ public:
bool strictModeEnabled() { return d_strictMode; }
+ void allowIncludeFile() { d_canIncludeFile = true; }
+ void disallowIncludeFile() { d_canIncludeFile = false; }
+ bool canIncludeFile() const { return d_canIncludeFile; }
+
/**
* Returns a variable, given a name.
*
@@ -285,7 +312,13 @@ public:
* @throws ParserException if checks are enabled and the check fails
*/
void checkDeclaration(const std::string& name, DeclarationCheck check,
- SymbolType type = SYM_VARIABLE) throw(ParserException);
+ SymbolType type = SYM_VARIABLE,
+ std::string notes = "") throw(ParserException);
+
+ /**
+ * Reserve a symbol at the assertion level.
+ */
+ void reserveSymbolAtAssertionLevel(const std::string& name);
/**
* Checks whether the given name is bound to a function.
@@ -326,14 +359,14 @@ public:
/** Create a new CVC4 variable expression of the given type. */
Expr mkVar(const std::string& name, const Type& type,
- bool levelZero = false);
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/**
* Create a set of new CVC4 variable expressions of the given type.
*/
std::vector<Expr>
mkVars(const std::vector<std::string> names, const Type& type,
- bool levelZero = false);
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/** Create a new CVC4 bound variable expression of the given type. */
Expr mkBoundVar(const std::string& name, const Type& type);
@@ -345,18 +378,19 @@ public:
/** Create a new CVC4 function expression of the given type. */
Expr mkFunction(const std::string& name, const Type& type,
- bool levelZero = false);
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/**
* Create a new CVC4 function expression of the given type,
* appending a unique index to its name. (That's the ONLY
* difference between mkAnonymousFunction() and mkFunction()).
*/
- Expr mkAnonymousFunction(const std::string& prefix, const Type& type);
+ Expr mkAnonymousFunction(const std::string& prefix, const Type& type,
+ uint32_t flags = ExprManager::VAR_FLAG_NONE);
/** Create a new variable definition (e.g., from a let binding). */
void defineVar(const std::string& name, const Expr& val,
- bool levelZero = false);
+ bool levelZero = false);
/** Create a new function definition (e.g., from a define-fun). */
void defineFunction(const std::string& name, const Expr& val,
@@ -377,7 +411,8 @@ public:
/**
* Creates a new sort with the given name.
*/
- SortType mkSort(const std::string& name);
+ SortType mkSort(const std::string& name,
+ uint32_t flags = ExprManager::SORT_FLAG_NONE);
/**
* Creates a new sort constructor with the given name and arity.
@@ -462,6 +497,11 @@ public:
d_input->parseError(msg);
}
+ /** Unexpectedly encountered an EOF */
+ inline void unexpectedEOF(const std::string& msg) throw(ParserException) {
+ d_input->parseError(msg, true);
+ }
+
/**
* If we are parsing only, don't raise an exception; if we are not,
* raise a parse error with the given message. There is no actual
@@ -482,8 +522,25 @@ public:
}
}
- inline void pushScope() { d_symtab->pushScope(); }
- inline void popScope() { d_symtab->popScope(); }
+ /**
+ * Gets the current declaration level.
+ */
+ inline size_t scopeLevel() const { return d_symtab->getLevel(); }
+
+ inline void pushScope(bool bindingLevel = false) {
+ d_symtab->pushScope();
+ if(!bindingLevel) {
+ d_assertionLevel = scopeLevel();
+ }
+ }
+
+ inline void popScope() {
+ d_symtab->popScope();
+ if(scopeLevel() < d_assertionLevel) {
+ d_assertionLevel = scopeLevel();
+ d_reservedSymbols.clear();
+ }
+ }
/**
* Set the current symbol table used by this parser.
@@ -527,13 +584,6 @@ public:
}
/**
- * Gets the current declaration level.
- */
- inline size_t getDeclarationLevel() const throw() {
- return d_symtab->getLevel();
- }
-
- /**
* An expression stream interface for a parser. This stream simply
* pulls expressions from the given Parser object.
*
diff --git a/src/parser/parser_builder.cpp b/src/parser/parser_builder.cpp
index 721337c9e..cb8c0d4f6 100644
--- a/src/parser/parser_builder.cpp
+++ b/src/parser/parser_builder.cpp
@@ -54,6 +54,7 @@ void ParserBuilder::init(ExprManager* exprManager,
d_exprManager = exprManager;
d_checksEnabled = true;
d_strictMode = false;
+ d_canIncludeFile = true;
d_mmap = false;
d_parseOnly = false;
}
@@ -102,6 +103,12 @@ Parser* ParserBuilder::build()
parser->disableChecks();
}
+ if( d_canIncludeFile ) {
+ parser->allowIncludeFile();
+ } else {
+ parser->disallowIncludeFile();
+ }
+
return parser;
}
@@ -146,7 +153,8 @@ ParserBuilder& ParserBuilder::withOptions(const Options& options) {
.withMmap(options[options::memoryMap])
.withChecks(options[options::semanticChecks])
.withStrictMode(options[options::strictParsing])
- .withParseOnly(options[options::parseOnly]);
+ .withParseOnly(options[options::parseOnly])
+ .withIncludeFile(options[options::canIncludeFile]);
}
ParserBuilder& ParserBuilder::withStrictMode(bool flag) {
@@ -154,6 +162,11 @@ ParserBuilder& ParserBuilder::withStrictMode(bool flag) {
return *this;
}
+ParserBuilder& ParserBuilder::withIncludeFile(bool flag) {
+ d_canIncludeFile = flag;
+ return *this;
+}
+
ParserBuilder& ParserBuilder::withStreamInput(std::istream& input) {
d_inputType = STREAM_INPUT;
d_streamInput = &input;
diff --git a/src/parser/parser_builder.h b/src/parser/parser_builder.h
index 75e2b4fbe..b6e15b2ff 100644
--- a/src/parser/parser_builder.h
+++ b/src/parser/parser_builder.h
@@ -71,6 +71,9 @@ class CVC4_PUBLIC ParserBuilder {
/** Should we parse in strict mode? */
bool d_strictMode;
+ /** Should we allow include-file commands? */
+ bool d_canIncludeFile;
+
/** Should we memory-map a file input? */
bool d_mmap;
@@ -146,6 +149,13 @@ public:
*/
ParserBuilder& withStrictMode(bool flag = true);
+ /**
+ * Should the include-file commands be enabled?
+ *
+ * (Default: yes)
+ */
+ ParserBuilder& withIncludeFile(bool flag = true);
+
/** Set the parser to use the given stream for its input. */
ParserBuilder& withStreamInput(std::istream& input);
diff --git a/src/parser/smt1/smt1.cpp b/src/parser/smt1/smt1.cpp
index 41b0523bd..c9bbd3860 100644
--- a/src/parser/smt1/smt1.cpp
+++ b/src/parser/smt1/smt1.cpp
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Morgan Deters
** Major contributors: Christopher L. Conway
- ** Minor contributors (to current version): Tim King, Dejan Jovanovic, Clark Barrett
+ ** Minor contributors (to current version): Tim King, Dejan Jovanovic, Clark Barrett, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -39,6 +39,7 @@ std::hash_map<const std::string, Smt1::Logic, CVC4::StringHashFunction> Smt1::ne
logicMap["QF_NIA"] = QF_NIA;
logicMap["QF_NRA"] = QF_NRA;
logicMap["QF_RDL"] = QF_RDL;
+ logicMap["QF_S"] = QF_S;
logicMap["QF_SAT"] = QF_SAT;
logicMap["QF_UF"] = QF_UF;
logicMap["QF_UFIDL"] = QF_UFIDL;
@@ -180,6 +181,10 @@ void Smt1::setLogic(const std::string& name) {
d_logic = toLogic(name);
switch(d_logic) {
+ case QF_S:
+ throw ParserException("Strings theory unsupported in SMT-LIBv1 front-end; try SMT-LIBv2.");
+ break;
+
case QF_AX:
addTheory(THEORY_ARRAYS_EX);
break;
diff --git a/src/parser/smt1/smt1.h b/src/parser/smt1/smt1.h
index d6961371a..f96a4e810 100644
--- a/src/parser/smt1/smt1.h
+++ b/src/parser/smt1/smt1.h
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Morgan Deters
** Major contributors: Christopher L. Conway
- ** Minor contributors (to current version): Clark Barrett
+ ** Minor contributors (to current version): Clark Barrett, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -52,6 +52,7 @@ public:
QF_NIA,
QF_NRA,
QF_RDL,
+ QF_S, // nonstandard (for string theory)
QF_SAT,
QF_UF,
QF_UFIDL,
@@ -82,6 +83,7 @@ public:
THEORY_INT_INT_REAL_ARRAY_ARRAYS_EX,
THEORY_REALS,
THEORY_REALS_INTS,
+ THEORY_STRINGS,
THEORY_QUANTIFIERS
};
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 8dcde2483..c84046570 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Christopher L. Conway
** Major contributors: Morgan Deters
- ** Minor contributors (to current version): Dejan Jovanovic, Andrew Reynolds, Francois Bobot
+ ** Minor contributors (to current version): Dejan Jovanovic, Andrew Reynolds, Francois Bobot, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -133,6 +133,41 @@ using namespace CVC4::parser;
#define MK_CONST EXPR_MANAGER->mkConst
#define UNSUPPORTED PARSER_STATE->unimplementedFeature
+static bool isClosed(Expr e, std::set<Expr>& free, std::hash_set<Expr, ExprHashFunction>& closedCache) {
+ if(closedCache.find(e) != closedCache.end()) {
+ return true;
+ }
+
+ if(e.getKind() == kind::FORALL || e.getKind() == kind::EXISTS || e.getKind() == kind::LAMBDA) {
+ isClosed(e[1], free, closedCache);
+ for(Expr::const_iterator i = e[0].begin(); i != e[0].end(); ++i) {
+ free.erase((*i)[0]);
+ }
+ } else if(e.getKind() == kind::BOUND_VARIABLE) {
+ free.insert(e);
+ return false;
+ } else {
+ if(e.hasOperator()) {
+ isClosed(e.getOperator(), free, closedCache);
+ }
+ for(Expr::const_iterator i = e.begin(); i != e.end(); ++i) {
+ isClosed(*i, free, closedCache);
+ }
+ }
+
+ if(free.empty()) {
+ closedCache.insert(e);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static inline bool isClosed(Expr e, std::set<Expr>& free) {
+ std::hash_set<Expr, ExprHashFunction> cache;
+ return isClosed(e, free, cache);
+}
+
}/* parser::postinclude */
/**
@@ -153,7 +188,26 @@ parseExpr returns [CVC4::parser::smt2::myExpr expr]
* @return the parsed command, or NULL if we've reached the end of the input
*/
parseCommand returns [CVC4::Command* cmd = NULL]
+@declarations {
+ std::string name;
+}
: LPAREN_TOK c = command RPAREN_TOK { $cmd = c; }
+
+ /* This extended command has to be in the outermost production so that
+ * the RPAREN_TOK is properly eaten and we are in a good state to read
+ * the included file's tokens. */
+ | LPAREN_TOK INCLUDE_TOK str[name] RPAREN_TOK
+ { if(!PARSER_STATE->canIncludeFile()) {
+ PARSER_STATE->parseError("include-file feature was disabled for this run.");
+ }
+ if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("Extended commands are not permitted while operating in strict compliance mode.");
+ }
+ PARSER_STATE->includeFile(name);
+ // The command of the included file will be produced at the next parseCommand() call
+ cmd = new EmptyCommand("include::" + name);
+ }
+
| EOF { $cmd = 0; }
;
@@ -188,9 +242,8 @@ command returns [CVC4::Command* cmd = NULL]
GET_INFO_TOK KEYWORD
{ cmd = new GetInfoCommand(AntlrInput::tokenText($KEYWORD).c_str() + 1); }
| /* set-option */
- SET_OPTION_TOK KEYWORD symbolicExpr[sexpr]
- { name = AntlrInput::tokenText($KEYWORD);
- PARSER_STATE->setOption(name.c_str() + 1, sexpr);
+ SET_OPTION_TOK keyword[name] symbolicExpr[sexpr]
+ { PARSER_STATE->setOption(name.c_str() + 1, sexpr);
cmd = new SetOptionCommand(name.c_str() + 1, sexpr); }
| /* get-option */
GET_OPTION_TOK KEYWORD
@@ -216,7 +269,7 @@ command returns [CVC4::Command* cmd = NULL]
symbol[name,CHECK_UNDECLARED,SYM_SORT]
{ PARSER_STATE->checkUserSymbol(name); }
LPAREN_TOK symbolList[names,CHECK_NONE,SYM_SORT] RPAREN_TOK
- { PARSER_STATE->pushScope();
+ { PARSER_STATE->pushScope(true);
for(std::vector<std::string>::const_iterator i = names.begin(),
iend = names.end();
i != iend;
@@ -262,7 +315,7 @@ command returns [CVC4::Command* cmd = NULL]
}
t = EXPR_MANAGER->mkFunctionType(sorts, t);
}
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -275,7 +328,7 @@ command returns [CVC4::Command* cmd = NULL]
// declare the name down here (while parsing term, signature
// must not be extended with the name itself; no recursion
// permitted)
- Expr func = PARSER_STATE->mkFunction(name, t);
+ Expr func = PARSER_STATE->mkFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, terms, expr);
}
| /* value query */
@@ -284,23 +337,29 @@ command returns [CVC4::Command* cmd = NULL]
{ $cmd = new GetValueCommand(terms); }
| /* get-assignment */
GET_ASSIGNMENT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetAssignmentCommand; }
+ { cmd = new GetAssignmentCommand(); }
| /* assertion */
ASSERT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
term[expr, expr2]
{ cmd = new AssertCommand(expr); }
- | /* checksat */
+ | /* check-sat */
CHECKSAT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new CheckSatCommand(MK_CONST(bool(true))); }
+ ( term[expr, expr2]
+ { if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("Extended commands (such as check-sat with an argument) are not permitted while operating in strict compliance mode.");
+ }
+ }
+ | { expr = MK_CONST(bool(true)); } )
+ { cmd = new CheckSatCommand(expr); }
| /* get-assertions */
GET_ASSERTIONS_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetAssertionsCommand; }
+ { cmd = new GetAssertionsCommand(); }
| /* get-proof */
GET_PROOF_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetProofCommand; }
+ { cmd = new GetProofCommand(); }
| /* get-unsat-core */
GET_UNSAT_CORE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetUnsatCoreCommand; }
+ { cmd = new GetUnsatCoreCommand(); }
| /* push */
PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( k=INTEGER_LITERAL
@@ -314,7 +373,9 @@ command returns [CVC4::Command* cmd = NULL]
CommandSequence* seq = new CommandSequence();
do {
PARSER_STATE->pushScope();
- seq->addCommand(new PushCommand());
+ Command* c = new PushCommand();
+ c->setMuted(n > 1);
+ seq->addCommand(c);
} while(--n > 0);
cmd = seq;
}
@@ -322,12 +383,15 @@ command returns [CVC4::Command* cmd = NULL]
| { if(PARSER_STATE->strictModeEnabled()) {
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to PUSH. Maybe you want (push 1)?");
} else {
- cmd = new PushCommand;
+ cmd = new PushCommand();
}
} )
| POP_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( k=INTEGER_LITERAL
{ unsigned n = AntlrInput::tokenToUnsigned(k);
+ if(n > PARSER_STATE->scopeLevel()) {
+ PARSER_STATE->parseError("Attempted to pop above the top stack frame.");
+ }
if(n == 0) {
cmd = new EmptyCommand();
} else if(n == 1) {
@@ -337,7 +401,9 @@ command returns [CVC4::Command* cmd = NULL]
CommandSequence* seq = new CommandSequence();
do {
PARSER_STATE->popScope();
- seq->addCommand(new PopCommand());
+ Command* c = new PopCommand();
+ c->setMuted(n > 1);
+ seq->addCommand(c);
} while(--n > 0);
cmd = seq;
}
@@ -345,11 +411,11 @@ command returns [CVC4::Command* cmd = NULL]
| { if(PARSER_STATE->strictModeEnabled()) {
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to POP. Maybe you want (pop 1)?");
} else {
- cmd = new PopCommand;
+ cmd = new PopCommand();
}
} )
| EXIT_TOK
- { cmd = new QuitCommand; }
+ { cmd = new QuitCommand(); }
/* CVC4-extended SMT-LIB commands */
| extendedCommand[cmd]
@@ -385,8 +451,8 @@ extendedCommand[CVC4::Command*& cmd]
* --smtlib2 compliance mode. */
: DECLARE_DATATYPES_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ /* open a scope to keep the UnresolvedTypes contained */
- PARSER_STATE->pushScope(); }
- LPAREN_TOK /* parametric sorts */
+ PARSER_STATE->pushScope(true); }
+ LPAREN_TOK /* parametric sorts */
( symbol[name,CHECK_UNDECLARED,SYM_SORT] {
sorts.push_back( PARSER_STATE->mkSort(name) ); }
)*
@@ -396,7 +462,7 @@ extendedCommand[CVC4::Command*& cmd]
cmd = new DatatypeDeclarationCommand(PARSER_STATE->mkMutualDatatypeTypes(dts)); }
| /* get model */
GET_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetModelCommand; }
+ { cmd = new GetModelCommand(); }
| ECHO_TOK
( simpleSymbolicExpr[sexpr]
{ std::stringstream ss;
@@ -465,7 +531,7 @@ extendedCommand[CVC4::Command*& cmd]
( symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
{ PARSER_STATE->checkUserSymbol(name); }
term[e,e2]
- { Expr func = PARSER_STATE->mkFunction(name, e.getType());
+ { Expr func = PARSER_STATE->mkFunction(name, e.getType(), ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, e);
}
| LPAREN_TOK
@@ -474,7 +540,7 @@ extendedCommand[CVC4::Command*& cmd]
sortedVarList[sortedVarNames] RPAREN_TOK
{ /* add variables to parser state before parsing term */
Debug("parser") << "define fun: '" << name << "'" << std::endl;
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -499,7 +565,7 @@ extendedCommand[CVC4::Command*& cmd]
}
t = EXPR_MANAGER->mkFunctionType(sorts, t);
}
- Expr func = PARSER_STATE->mkFunction(name, t);
+ Expr func = PARSER_STATE->mkFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, terms, e);
}
)
@@ -521,7 +587,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
{
kind = CVC4::kind::RR_REWRITE;
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -562,7 +628,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
| rewritePropaKind[kind]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
{
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -631,6 +697,7 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
@declarations {
CVC4::Kind k;
std::string s;
+ std::vector<unsigned int> s_vec;
}
: INTEGER_LITERAL
{ sexpr = SExpr(Integer(AntlrInput::tokenText($INTEGER_LITERAL))); }
@@ -638,8 +705,17 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
{ sexpr = SExpr(AntlrInput::tokenToRational($DECIMAL_LITERAL)); }
| str[s]
{ sexpr = SExpr(s); }
+// | LPAREN_TOK STRCST_TOK
+// ( INTEGER_LITERAL {
+// s_vec.push_back( atoi( AntlrInput::tokenText($INTEGER_LITERAL) ) + 65 );
+// } )* RPAREN_TOK
+// {
+// sexpr = SExpr( MK_CONST( ::CVC4::String(s_vec) ) );
+// }
| symbol[s,CHECK_NONE,SYM_SORT]
{ sexpr = SExpr(SExpr::Keyword(s)); }
+ | tok=(ASSERT_TOK | CHECKSAT_TOK | DECLARE_FUN_TOK | DECLARE_SORT_TOK | DEFINE_FUN_TOK | DEFINE_SORT_TOK | GET_VALUE_TOK | GET_ASSIGNMENT_TOK | GET_ASSERTIONS_TOK | GET_PROOF_TOK | GET_UNSAT_CORE_TOK | EXIT_TOK | SET_LOGIC_TOK | SET_INFO_TOK | GET_INFO_TOK | SET_OPTION_TOK | GET_OPTION_TOK | PUSH_TOK | POP_TOK | DECLARE_DATATYPES_TOK | GET_MODEL_TOK | ECHO_TOK | REWRITE_RULE_TOK | REDUCTION_RULE_TOK | PROPAGATION_RULE_TOK | SIMPLIFY_TOK)
+ { sexpr = SExpr(SExpr::Keyword(AntlrInput::tokenText($tok))); }
| builtinOp[k]
{ std::stringstream ss;
ss << Expr::setlanguage(CVC4::language::output::LANG_SMTLIB_V2) << EXPR_MANAGER->mkConst(k);
@@ -647,6 +723,11 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
}
;
+keyword[std::string& s]
+ : KEYWORD
+ { s = AntlrInput::tokenText($KEYWORD); }
+ ;
+
simpleSymbolicExpr[CVC4::SExpr& sexpr]
: simpleSymbolicExprNoKeyword[sexpr]
| KEYWORD
@@ -671,7 +752,7 @@ symbolicExpr[CVC4::SExpr& sexpr]
term[CVC4::Expr& expr, CVC4::Expr& expr2]
@init {
Debug("parser") << "term: " << AntlrInput::tokenText(LT(1)) << std::endl;
- Kind kind;
+ Kind kind = kind::NULL_EXPR;
Expr op;
std::string name;
std::vector<Expr> args;
@@ -684,6 +765,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
std::hash_set<std::string, StringHashFunction> names;
std::vector< std::pair<std::string, Expr> > binders;
Type type;
+ std::string s;
}
: /* a built-in operator application */
LPAREN_TOK builtinOp[kind] termList[args,expr] RPAREN_TOK
@@ -699,19 +781,38 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
(kind == CVC4::kind::AND || kind == CVC4::kind::OR) &&
args.size() == 1) {
/* Unary AND/OR can be replaced with the argument.
- It just so happens expr should already by the only argument. */
+ * It just so happens expr should already be the only argument. */
assert( expr == args[0] );
} else if( CVC4::kind::isAssociative(kind) &&
args.size() > EXPR_MANAGER->maxArity(kind) ) {
/* Special treatment for associative operators with lots of children */
- expr = EXPR_MANAGER->mkAssociative(kind,args);
+ expr = EXPR_MANAGER->mkAssociative(kind, args);
} else if( kind == CVC4::kind::MINUS && args.size() == 1 ) {
expr = MK_EXPR(CVC4::kind::UMINUS, args[0]);
+ } else if( ( kind == CVC4::kind::XOR || kind == CVC4::kind::MINUS ) &&
+ args.size() > 2 ) {
+ /* left-associative, but CVC4 internally only supports 2 args */
+ expr = args[0];
+ for(size_t i = 1; i < args.size(); ++i) {
+ expr = MK_EXPR(kind, expr, args[i]);
+ }
+ } else if( kind == CVC4::kind::IMPLIES && args.size() > 2 ) {
+ /* right-associative, but CVC4 internally only supports 2 args */
+ expr = args[args.size() - 1];
+ for(size_t i = args.size() - 1; i > 0;) {
+ expr = MK_EXPR(kind, args[--i], expr);
+ }
} else if( ( kind == CVC4::kind::IFF || kind == CVC4::kind::EQUAL ||
kind == CVC4::kind::LT || kind == CVC4::kind::GT ||
kind == CVC4::kind::LEQ || kind == CVC4::kind::GEQ ) &&
args.size() > 2 ) {
- expr = MK_EXPR(CVC4::kind::CHAIN, MK_CONST(kind), args);
+ /* "chainable", but CVC4 internally only supports 2 args */
+ expr = MK_EXPR(MK_CONST(Chain(kind)), args);
+ } else if( PARSER_STATE->strictModeEnabled() && kind == CVC4::kind::ABS &&
+ args.size() == 1 && !args[0].getType().isInteger() ) {
+ /* first, check that ABS is even defined in this logic */
+ PARSER_STATE->checkOperator(kind, args.size());
+ PARSER_STATE->parseError("abs can only be applied to Int, not Real, while in strict SMT-LIB compliance mode");
} else {
PARSER_STATE->checkOperator(kind, args.size());
expr = MK_EXPR(kind, args);
@@ -726,7 +827,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
v.push_back(MK_EXPR( CVC4::kind::APPLY_TYPE_ASCRIPTION,
MK_CONST(AscriptionType(dtc.getSpecializedConstructorType(type))), f.getOperator() ));
v.insert(v.end(), f.begin(), f.end());
- f = MK_EXPR(CVC4::kind::APPLY_CONSTRUCTOR, v);
+ expr = MK_EXPR(CVC4::kind::APPLY_CONSTRUCTOR, v);
} else {
if(f.getType() != type) {
PARSER_STATE->parseError("Type ascription not satisfied.");
@@ -736,7 +837,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
| LPAREN_TOK quantOp[kind]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
{
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
sortedVarNames.begin(), iend = sortedVarNames.end();
i != iend;
@@ -769,6 +870,10 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
expr = MK_EXPR(kind, args);
}
}
+ //| /* substring */
+ //LPAREN_TOK STRSUB_TOK n1=INTEGER_LITERAL n2=INTEGER_LITERAL RPAREN_TOK
+ //{
+ //}
| /* A non-built-in function application */
LPAREN_TOK
functionName[name, CHECK_DECLARED]
@@ -801,11 +906,12 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
| /* An indexed function application */
LPAREN_TOK indexedFunctionName[op] termList[args,expr] RPAREN_TOK
- { expr = MK_EXPR(op, args); }
-
+ { expr = MK_EXPR(op, args);
+ PARSER_STATE->checkOperator(expr.getKind(), args.size());
+ }
| /* a let binding */
LPAREN_TOK LET_TOK LPAREN_TOK
- { PARSER_STATE->pushScope(); }
+ { PARSER_STATE->pushScope(true); }
( LPAREN_TOK symbol[name,CHECK_NONE,SYM_VARIABLE] term[expr, f2] RPAREN_TOK
// this is a parallel let, so we have to save up all the contributions
// of the let and define them only later on
@@ -918,6 +1024,9 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
std::string binString = AntlrInput::tokenTextSubstr($BINARY_LITERAL, 2);
expr = MK_CONST( BitVector(binString, 2) ); }
+ | str[s]
+ { expr = MK_CONST( ::CVC4::String(s) ); }
+
// NOTE: Theory constants go here
;
@@ -971,10 +1080,24 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
| ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr]
{
attr = std::string(":named");
+ if(!sexpr.isKeyword()) {
+ PARSER_STATE->parseError("improperly formed :named annotation");
+ }
std::string name = sexpr.getValue();
- // FIXME ensure expr is a closed subterm
- // check that sexpr is a fresh function symbol
- PARSER_STATE->checkDeclaration(name, CHECK_UNDECLARED, SYM_VARIABLE);
+ PARSER_STATE->checkUserSymbol(name);
+ // ensure expr is a closed subterm
+ std::set<Expr> freeVars;
+ if(!isClosed(expr, freeVars)) {
+ assert(!freeVars.empty());
+ std::stringstream ss;
+ ss << ":named annotations can only name terms that are closed; this one contains free variables:";
+ for(std::set<Expr>::const_iterator i = freeVars.begin(); i != freeVars.end(); ++i) {
+ ss << " " << *i;
+ }
+ PARSER_STATE->parseError(ss.str());
+ }
+ // check that sexpr is a fresh function symbol, and reserve it
+ PARSER_STATE->reserveSymbolAtAssertionLevel(name);
// define it
Expr func = PARSER_STATE->mkFunction(name, expr.getType());
// bind name to expr with define-fun
@@ -1003,6 +1126,13 @@ indexedFunctionName[CVC4::Expr& op]
{ op = MK_CONST(BitVectorRotateLeft(AntlrInput::tokenToUnsigned($n))); }
| 'rotate_right' n=INTEGER_LITERAL
{ op = MK_CONST(BitVectorRotateRight(AntlrInput::tokenToUnsigned($n))); }
+ | DIVISIBLE_TOK n=INTEGER_LITERAL
+ { op = MK_CONST(Divisible(AntlrInput::tokenToUnsigned($n))); }
+ | INT2BV_TOK n=INTEGER_LITERAL
+ { op = MK_CONST(IntToBitVector(AntlrInput::tokenToUnsigned($n)));
+ if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("bv2nat and int2bv are not part of SMT-LIB, and aren't available in SMT-LIB strict compliance mode");
+ } }
| badIndexedFunctionName
)
RPAREN_TOK
@@ -1075,6 +1205,10 @@ builtinOp[CVC4::Kind& kind]
| DIV_TOK { $kind = CVC4::kind::DIVISION; }
| INTS_DIV_TOK { $kind = CVC4::kind::INTS_DIVISION; }
| INTS_MOD_TOK { $kind = CVC4::kind::INTS_MODULUS; }
+ | ABS_TOK { $kind = CVC4::kind::ABS; }
+ | IS_INT_TOK { $kind = CVC4::kind::IS_INTEGER; }
+ | TO_INT_TOK { $kind = CVC4::kind::TO_INTEGER; }
+ | TO_REAL_TOK { $kind = CVC4::kind::TO_REAL; }
| SELECT_TOK { $kind = CVC4::kind::SELECT; }
| STORE_TOK { $kind = CVC4::kind::STORE; }
@@ -1109,6 +1243,22 @@ builtinOp[CVC4::Kind& kind]
| BVSGT_TOK { $kind = CVC4::kind::BITVECTOR_SGT; }
| BVSGE_TOK { $kind = CVC4::kind::BITVECTOR_SGE; }
+ | BV2NAT_TOK { $kind = CVC4::kind::BITVECTOR_TO_NAT;
+ if(PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("bv2nat and int2bv are not part of SMT-LIB, and aren't available in SMT-LIB strict compliance mode");
+ } }
+
+ | STRCON_TOK { $kind = CVC4::kind::STRING_CONCAT; }
+ | STRLEN_TOK { $kind = CVC4::kind::STRING_LENGTH; }
+ | STRINRE_TOK { $kind = CVC4::kind::STRING_IN_REGEXP; }
+ | STRTORE_TOK { $kind = CVC4::kind::STRING_TO_REGEXP; }
+ | RECON_TOK { $kind = CVC4::kind::REGEXP_CONCAT; }
+ | REOR_TOK { $kind = CVC4::kind::REGEXP_OR; }
+ | REINTER_TOK { $kind = CVC4::kind::REGEXP_INTER; }
+ | RESTAR_TOK { $kind = CVC4::kind::REGEXP_STAR; }
+ | REPLUS_TOK { $kind = CVC4::kind::REGEXP_PLUS; }
+ | REOPT_TOK { $kind = CVC4::kind::REGEXP_OPT; }
+
// NOTE: Theory operators go here
;
@@ -1200,6 +1350,9 @@ sortSymbol[CVC4::Type& t, CVC4::parser::DeclarationCheck check]
if( numerals.size() != 1 ) {
PARSER_STATE->parseError("Illegal bitvector type.");
}
+ if(numerals.front() == 0) {
+ PARSER_STATE->parseError("Illegal bitvector size: 0");
+ }
t = EXPR_MANAGER->mkBitVectorType(numerals.front());
} else {
std::stringstream ss;
@@ -1209,21 +1362,20 @@ sortSymbol[CVC4::Type& t, CVC4::parser::DeclarationCheck check]
}
| LPAREN_TOK symbol[name,CHECK_NONE,SYM_SORT] sortList[args] RPAREN_TOK
{
- if( check == CHECK_DECLARED || PARSER_STATE->isDeclared(name, SYM_SORT)) {
- if( name == "Array" ) {
- if( args.size() != 2 ) {
- PARSER_STATE->parseError("Illegal array type.");
- }
- t = EXPR_MANAGER->mkArrayType( args[0], args[1] );
- } else {
- t = PARSER_STATE->getSort(name, args);
+ if(name == "Array") {
+ if(args.size() != 2) {
+ PARSER_STATE->parseError("Illegal array type.");
}
- }else{
- //make unresolved type
+ t = EXPR_MANAGER->mkArrayType( args[0], args[1] );
+ } else if(check == CHECK_DECLARED ||
+ PARSER_STATE->isDeclared(name, SYM_SORT)) {
+ t = PARSER_STATE->getSort(name, args);
+ } else {
+ // make unresolved type
if(args.empty()) {
t = PARSER_STATE->mkUnresolvedType(name);
Debug("parser-param") << "param: make unres type " << name << std::endl;
- }else{
+ } else {
t = PARSER_STATE->mkUnresolvedTypeConstructor(name,args);
t = SortConstructorType(t).instantiate( args );
Debug("parser-param") << "param: make unres param type " << name << " " << args.size() << " "
@@ -1271,6 +1423,8 @@ symbol[std::string& id,
PARSER_STATE->checkDeclaration(id, check, type);
}
}
+ | UNTERMINATED_QUOTED_SYMBOL EOF
+ { PARSER_STATE->unexpectedEOF("unterminated |quoted| symbol"); }
;
/**
@@ -1294,7 +1448,7 @@ datatypeDef[std::vector<CVC4::Datatype>& datatypes, std::vector< CVC4::Type >& p
* datatypes won't work, because this type will already be
* "defined" as an unresolved type; don't worry, we check
* below. */
- : symbol[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(); }
+ : symbol[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(true); }
/* ( '[' symbol[id2,CHECK_UNDECLARED,SYM_SORT] {
t = PARSER_STATE->mkSort(id2);
params.push_back( t );
@@ -1344,7 +1498,8 @@ selector[CVC4::DatatypeConstructor& ctor]
}
: symbol[id,CHECK_UNDECLARED,SYM_SORT] sortSymbol[t,CHECK_NONE]
{ ctor.addArg(id, t);
- Debug("parser-idt") << "selector: " << id.c_str() << std::endl;
+ Debug("parser-idt") << "selector: " << id.c_str()
+ << " of type " << t << std::endl;
}
;
@@ -1389,6 +1544,7 @@ DECLARE_PREDS_TOK : 'declare-preds';
DEFINE_TOK : 'define';
DECLARE_CONST_TOK : 'declare-const';
SIMPLIFY_TOK : 'simplify';
+INCLUDE_TOK : 'include';
// attributes
ATTRIBUTE_PATTERN_TOK : ':pattern';
@@ -1407,6 +1563,7 @@ FORALL_TOK : 'forall';
GREATER_THAN_TOK : '>';
GREATER_THAN_EQUAL_TOK : '>=';
IMPLIES_TOK : '=>';
+IS_INT_TOK : 'is_int';
LESS_THAN_TOK : '<';
LESS_THAN_EQUAL_TOK : '<=';
MINUS_TOK : '-';
@@ -1419,10 +1576,15 @@ SELECT_TOK : 'select';
STAR_TOK : '*';
STORE_TOK : 'store';
// TILDE_TOK : '~';
+TO_INT_TOK : 'to_int';
+TO_REAL_TOK : 'to_real';
XOR_TOK : 'xor';
INTS_DIV_TOK : 'div';
INTS_MOD_TOK : 'mod';
+ABS_TOK : 'abs';
+
+DIVISIBLE_TOK : 'divisible';
CONCAT_TOK : 'concat';
BVNOT_TOK : 'bvnot';
@@ -1453,6 +1615,22 @@ BVSLT_TOK : 'bvslt';
BVSLE_TOK : 'bvsle';
BVSGT_TOK : 'bvsgt';
BVSGE_TOK : 'bvsge';
+BV2NAT_TOK : 'bv2nat';
+INT2BV_TOK : 'int2bv';
+
+//STRING
+//STRCST_TOK : 'str.cst';
+STRCON_TOK : 'str.++';
+STRLEN_TOK : 'str.len';
+//STRSUB_TOK : 'str.sub' ;
+STRINRE_TOK : 'str.in.re';
+STRTORE_TOK : 'str.to.re';
+RECON_TOK : 're.++';
+REOR_TOK : 're.or';
+REINTER_TOK : 're.itr';
+RESTAR_TOK : 're.*';
+REPLUS_TOK : 're.+';
+REOPT_TOK : 're.opt';
/**
* A sequence of printable ASCII characters (except backslash) that starts
@@ -1464,6 +1642,9 @@ BVSGE_TOK : 'bvsge';
QUOTED_SYMBOL
: '|' ~('|' | '\\')* '|'
;
+UNTERMINATED_QUOTED_SYMBOL
+ : '|' ~('|' | '\\')*
+ ;
/**
* Matches a keyword from the input. A keyword is a simple symbol prefixed
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index a7f7796cd..884502cf2 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -19,6 +19,11 @@
#include "parser/parser.h"
#include "parser/smt1/smt1.h"
#include "parser/smt2/smt2.h"
+#include "parser/antlr_input.h"
+
+// ANTLR defines these, which is really bad!
+#undef true
+#undef false
namespace CVC4 {
namespace parser {
@@ -36,7 +41,6 @@ void Smt2::addArithmeticOperators() {
addOperator(kind::MINUS);
addOperator(kind::UMINUS);
addOperator(kind::MULT);
- addOperator(kind::DIVISION);
addOperator(kind::LT);
addOperator(kind::LEQ);
addOperator(kind::GT);
@@ -80,6 +84,15 @@ void Smt2::addBitvectorOperators() {
addOperator(kind::BITVECTOR_SIGN_EXTEND);
addOperator(kind::BITVECTOR_ROTATE_LEFT);
addOperator(kind::BITVECTOR_ROTATE_RIGHT);
+
+ addOperator(kind::INT_TO_BITVECTOR);
+ addOperator(kind::BITVECTOR_TO_NAT);
+}
+
+void Smt2::addStringOperators() {
+ addOperator(kind::STRING_CONCAT);
+ addOperator(kind::STRING_LENGTH);
+ //addOperator(kind::STRING_IN_REGEXP);
}
void Smt2::addTheory(Theory theory) {
@@ -106,22 +119,36 @@ void Smt2::addTheory(Theory theory) {
case THEORY_REALS_INTS:
defineType("Real", getExprManager()->realType());
- // falling-through on purpose, to add Ints part of RealsInts
+ addOperator(kind::DIVISION);
+ addOperator(kind::TO_INTEGER);
+ addOperator(kind::IS_INTEGER);
+ addOperator(kind::TO_REAL);
+ // falling through on purpose, to add Ints part of Reals_Ints
case THEORY_INTS:
defineType("Int", getExprManager()->integerType());
addArithmeticOperators();
+ addOperator(kind::INTS_DIVISION);
+ addOperator(kind::INTS_MODULUS);
+ addOperator(kind::ABS);
+ addOperator(kind::DIVISIBLE);
break;
case THEORY_REALS:
defineType("Real", getExprManager()->realType());
addArithmeticOperators();
+ addOperator(kind::DIVISION);
break;
case THEORY_BITVECTORS:
addBitvectorOperators();
break;
+ case THEORY_STRINGS:
+ defineType("String", getExprManager()->stringType());
+ addStringOperators();
+ break;
+
case THEORY_QUANTIFIERS:
break;
@@ -138,135 +165,41 @@ bool Smt2::logicIsSet() {
void Smt2::setLogic(const std::string& name) {
d_logicSet = true;
- d_logic = Smt1::toLogic(name);
+ d_logic = name;
// Core theory belongs to every logic
addTheory(THEORY_CORE);
- switch(d_logic) {
- case Smt1::QF_SAT:
- /* No extra symbols necessary */
- break;
-
- case Smt1::QF_AX:
- addTheory(THEORY_ARRAYS);
- break;
-
- case Smt1::QF_IDL:
- case Smt1::QF_LIA:
- case Smt1::QF_NIA:
- addTheory(THEORY_INTS);
- break;
-
- case Smt1::QF_RDL:
- case Smt1::QF_LRA:
- case Smt1::QF_NRA:
- addTheory(THEORY_REALS);
- break;
-
- case Smt1::QF_UF:
- addOperator(kind::APPLY_UF);
- break;
-
- case Smt1::QF_UFIDL:
- case Smt1::QF_UFLIA:
- case Smt1::QF_UFNIA:// nonstandard logic
- addTheory(THEORY_INTS);
- addOperator(kind::APPLY_UF);
- break;
-
- case Smt1::QF_UFLRA:
- case Smt1::QF_UFNRA:
- addTheory(THEORY_REALS);
+ if(d_logic.isTheoryEnabled(theory::THEORY_UF)) {
addOperator(kind::APPLY_UF);
- break;
-
- case Smt1::QF_UFLIRA:// nonstandard logic
- case Smt1::QF_UFNIRA:// nonstandard logic
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- addTheory(THEORY_REALS);
- break;
-
- case Smt1::QF_BV:
- addTheory(THEORY_BITVECTORS);
- break;
-
- case Smt1::QF_ABV:
- addTheory(THEORY_ARRAYS);
- addTheory(THEORY_BITVECTORS);
- break;
-
- case Smt1::QF_UFBV:
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_BITVECTORS);
- break;
+ }
- case Smt1::QF_AUFBV:
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_ARRAYS);
- addTheory(THEORY_BITVECTORS);
- break;
+ if(d_logic.isTheoryEnabled(theory::THEORY_ARITH)) {
+ if(d_logic.areIntegersUsed()) {
+ if(d_logic.areRealsUsed()) {
+ addTheory(THEORY_REALS_INTS);
+ } else {
+ addTheory(THEORY_INTS);
+ }
+ } else if(d_logic.areRealsUsed()) {
+ addTheory(THEORY_REALS);
+ }
+ }
- case Smt1::QF_AUFBVLIA:
- addOperator(kind::APPLY_UF);
+ if(d_logic.isTheoryEnabled(theory::THEORY_ARRAY)) {
addTheory(THEORY_ARRAYS);
- addTheory(THEORY_BITVECTORS);
- addTheory(THEORY_INTS);
- break;
+ }
- case Smt1::QF_AUFBVLRA:
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_ARRAYS);
+ if(d_logic.isTheoryEnabled(theory::THEORY_BV)) {
addTheory(THEORY_BITVECTORS);
- addTheory(THEORY_REALS);
- break;
-
- case Smt1::QF_AUFLIA:
- addTheory(THEORY_ARRAYS);
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- break;
-
- case Smt1::QF_AUFLIRA:
- addTheory(THEORY_ARRAYS);
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- addTheory(THEORY_REALS);
- break;
+ }
- case Smt1::ALL_SUPPORTED:
- addTheory(THEORY_QUANTIFIERS);
- /* fall through */
- case Smt1::QF_ALL_SUPPORTED:
- addTheory(THEORY_ARRAYS);
- addOperator(kind::APPLY_UF);
- addTheory(THEORY_INTS);
- addTheory(THEORY_REALS);
- addTheory(THEORY_BITVECTORS);
- break;
+ if(d_logic.isTheoryEnabled(theory::THEORY_STRINGS)) {
+ addTheory(THEORY_STRINGS);
+ }
- case Smt1::AUFLIA:
- case Smt1::AUFLIRA:
- case Smt1::AUFNIRA:
- case Smt1::LRA:
- case Smt1::UFNIA:
- case Smt1::UFNIRA:
- case Smt1::UFLRA:
- if(d_logic != Smt1::AUFLIA && d_logic != Smt1::UFNIA) {
- addTheory(THEORY_REALS);
- }
- if(d_logic != Smt1::LRA) {
- addOperator(kind::APPLY_UF);
- if(d_logic != Smt1::UFLRA) {
- addTheory(THEORY_INTS);
- if(d_logic != Smt1::UFNIA && d_logic != Smt1::UFNIRA) {
- addTheory(THEORY_ARRAYS);
- }
- }
- }
+ if(d_logic.isQuantified()) {
addTheory(THEORY_QUANTIFIERS);
- break;
}
}/* Smt2::setLogic() */
@@ -297,5 +230,65 @@ void Smt2::checkThatLogicIsSet() {
}
}
+/* The include are managed in the lexer but called in the parser */
+// Inspired by http://www.antlr3.org/api/C/interop.html
+
+static bool newInputStream(const std::string& filename, pANTLR3_LEXER lexer) {
+ Debug("parser") << "Including " << filename << std::endl;
+ // Create a new input stream and take advantage of built in stream stacking
+ // in C target runtime.
+ //
+ pANTLR3_INPUT_STREAM in;
+#ifdef CVC4_ANTLR3_OLD_INPUT_STREAM
+ in = antlr3AsciiFileStreamNew((pANTLR3_UINT8) filename.c_str());
+#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
+ in = antlr3FileStreamNew((pANTLR3_UINT8) filename.c_str(), ANTLR3_ENC_8BIT);
+#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
+ if( in == NULL ) {
+ Debug("parser") << "Can't open " << filename << std::endl;
+ return false;
+ }
+ // Same thing as the predefined PUSHSTREAM(in);
+ lexer->pushCharStream(lexer, in);
+ // restart it
+ //lexer->rec->state->tokenStartCharIndex = -10;
+ //lexer->emit(lexer);
+
+ // Note that the input stream is not closed when it EOFs, I don't bother
+ // to do it here, but it is up to you to track streams created like this
+ // and destroy them when the whole parse session is complete. Remember that you
+ // don't want to do this until all tokens have been manipulated all the way through
+ // your tree parsers etc as the token does not store the text it just refers
+ // back to the input stream and trying to get the text for it will abort if you
+ // close the input stream too early.
+
+ //TODO what said before
+ return true;
+}
+
+void Smt2::includeFile(const std::string& filename) {
+ // security for online version
+ if(!canIncludeFile()) {
+ parseError("include-file feature was disabled for this run.");
+ }
+
+ // Get the lexer
+ AntlrInput* ai = static_cast<AntlrInput*>(getInput());
+ pANTLR3_LEXER lexer = ai->getAntlr3Lexer();
+ // get the name of the current stream "Does it work inside an include?"
+ const std::string inputName = ai->getInputStreamName();
+
+ // Find the directory of the current input file
+ std::string path;
+ size_t pos = inputName.rfind('/');
+ if(pos != std::string::npos) {
+ path = std::string(inputName, 0, pos + 1);
+ }
+ path.append(filename);
+ if(!newInputStream(path, lexer)) {
+ parseError("Couldn't open include file `" + path + "'");
+ }
+}
+
}/* CVC4::parser namespace */
}/* CVC4 namespace */
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 5762ff5f9..cc46efe07 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -21,6 +21,7 @@
#include "parser/parser.h"
#include "parser/smt1/smt1.h"
+#include "theory/logic_info.h"
#include "util/abstract_value.h"
#include <sstream>
@@ -43,11 +44,12 @@ public:
THEORY_REALS,
THEORY_REALS_INTS,
THEORY_QUANTIFIERS,
+ THEORY_STRINGS
};
private:
bool d_logicSet;
- Smt1::Logic d_logic;
+ LogicInfo d_logic;
protected:
Smt2(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -84,6 +86,8 @@ public:
}
}
+ void includeFile(const std::string& filename);
+
bool isAbstractValue(const std::string& name) {
return name.length() >= 2 && name[0] == '@' && name[1] != '0' &&
name.find_first_not_of("0123456789", 1) == std::string::npos;
@@ -94,12 +98,38 @@ public:
return getExprManager()->mkConst(AbstractValue(Integer(name.substr(1))));
}
+ /**
+ * Smt2 parser provides its own checkDeclaration, which does the
+ * same as the base, but with some more helpful errors.
+ */
+ void checkDeclaration(const std::string& name, DeclarationCheck check,
+ SymbolType type = SYM_VARIABLE,
+ std::string notes = "") throw(ParserException) {
+ // if the symbol is something like "-1", we'll give the user a helpful
+ // syntax hint. (-1 is a valid identifier in SMT-LIB, NOT unary minus.)
+ if( check != CHECK_DECLARED ||
+ name[0] != '-' ||
+ name.find_first_not_of("0123456789", 1) != std::string::npos ) {
+ this->Parser::checkDeclaration(name, check, type, notes);
+ return;
+ }
+
+ std::stringstream ss;
+ ss << notes
+ << "You may have intended to apply unary minus: `(- "
+ << name.substr(1)
+ << ")'\n";
+ this->Parser::checkDeclaration(name, check, type, ss.str());
+ }
+
private:
void addArithmeticOperators();
void addBitvectorOperators();
+ void addStringOperators();
+
};/* class Smt2 */
}/* CVC4::parser namespace */
diff --git a/src/parser/tptp/Tptp.g b/src/parser/tptp/Tptp.g
index 9e814b358..61e0999e9 100644
--- a/src/parser/tptp/Tptp.g
+++ b/src/parser/tptp/Tptp.g
@@ -27,7 +27,7 @@ options {
// Only lookahead of <= k requested (disable for LL* parsing)
// Note that CVC4's BoundedTokenBuffer requires a fixed k !
// If you change this k, change it also in tptp_input.cpp !
- k = 1;
+ k = 2;
}/* options */
@header {
@@ -102,6 +102,8 @@ using namespace CVC4::parser;
#include "util/output.h"
#include "util/rational.h"
#include <vector>
+#include <iterator>
+#include <algorithm>
using namespace CVC4;
using namespace CVC4::parser;
@@ -114,12 +116,12 @@ using namespace CVC4::parser;
#define EXPR_MANAGER PARSER_STATE->getExprManager()
#undef MK_EXPR
#define MK_EXPR EXPR_MANAGER->mkExpr
+#undef MK_EXPR_ASSOCIATIVE
+#define MK_EXPR_ASSOCIATIVE EXPR_MANAGER->mkAssociative
#undef MK_CONST
#define MK_CONST EXPR_MANAGER->mkConst
#define UNSUPPORTED PARSER_STATE->unimplementedFeature
-
-
}/* parser::postinclude */
/**
@@ -139,46 +141,81 @@ parseCommand returns [CVC4::Command* cmd = NULL]
@declarations {
Expr expr;
Tptp::FormulaRole fr;
- std::string name;
- std::string incl_args;
+ std::string name, inclSymbol;
}
// : LPAREN_TOK c = command RPAREN_TOK { $cmd = c; }
: CNF_TOK LPAREN_TOK nameN[name] COMMA_TOK formulaRole[fr] COMMA_TOK
- { PARSER_STATE->cnf=true; PARSER_STATE->pushScope(); }
+ { PARSER_STATE->cnf = true; PARSER_STATE->fof = false; PARSER_STATE->pushScope(); }
cnfFormula[expr]
{ PARSER_STATE->popScope();
std::vector<Expr> bvl = PARSER_STATE->getFreeVar();
- if(!bvl.empty()){
+ if(!bvl.empty()) {
expr = MK_EXPR(kind::FORALL,MK_EXPR(kind::BOUND_VAR_LIST,bvl),expr);
};
}
(COMMA_TOK anything*)? RPAREN_TOK DOT_TOK
{
- cmd = PARSER_STATE->makeCommand(fr,expr);
+ cmd = PARSER_STATE->makeCommand(fr, expr, /* cnf == */ true);
}
| FOF_TOK LPAREN_TOK nameN[name] COMMA_TOK formulaRole[fr] COMMA_TOK
- { PARSER_STATE->cnf=false; }
+ { PARSER_STATE->cnf = false; PARSER_STATE->fof = true; }
fofFormula[expr] (COMMA_TOK anything*)? RPAREN_TOK DOT_TOK
{
- cmd = PARSER_STATE->makeCommand(fr,expr);
+ cmd = PARSER_STATE->makeCommand(fr, expr, /* cnf == */ false);
}
+ | TFF_TOK LPAREN_TOK nameN[name] COMMA_TOK
+ ( TYPE_TOK COMMA_TOK tffTypedAtom[cmd]
+ | formulaRole[fr] COMMA_TOK
+ { PARSER_STATE->cnf = false; PARSER_STATE->fof = false; }
+ tffFormula[expr] (COMMA_TOK anything*)?
+ {
+ cmd = PARSER_STATE->makeCommand(fr, expr, /* cnf == */ false);
+ }
+ ) RPAREN_TOK DOT_TOK
| INCLUDE_TOK LPAREN_TOK unquotedFileName[name]
- ( COMMA_TOK LBRACK_TOK nameN[incl_args] ( COMMA_TOK nameN[incl_args] )* RBRACK_TOK )?
+ ( COMMA_TOK LBRACK_TOK nameN[inclSymbol]
+ ( COMMA_TOK nameN[inclSymbol] )* RBRACK_TOK )?
RPAREN_TOK DOT_TOK
- {
- PARSER_STATE->includeFile(name);
- // The command of the included file will be produce at the new parseCommand call
+ { /* TODO - implement symbol filtering for file inclusion.
+ * the following removes duplicates and "all", just need to pass it
+ * through to includeFile() and implement it there.
+ std::sort(inclArgs.begin(), inclArgs.end());
+ std::vector<std::string>::iterator it =
+ std::unique(inclArgs.begin(), inclArgs.end());
+ inclArgs.resize(std::distance(inclArgs.begin(), it));
+ it = std::lower_bound(inclArgs.begin(), inclArgs.end(), std::string("all"));
+ if(it != inclArgs.end() && *it == "all") {
+ inclArgs.erase(it);
+ }
+ */
+ PARSER_STATE->includeFile(name /* , inclArgs */ );
+ // The command of the included file will be produced at the next parseCommand() call
cmd = new EmptyCommand("include::" + name);
}
| EOF
{
- PARSER_STATE->preemptCommand(new CheckSatCommand(MK_CONST(bool(true))));
+ std::string filename = PARSER_STATE->getInput()->getInputStreamName();
+ size_t i = filename.find_last_of('/');
+ if(i != std::string::npos) {
+ filename = filename.substr(i + 1);
+ }
+ if(filename.substr(filename.length() - 2) == ".p") {
+ filename = filename.substr(0, filename.length() - 2);
+ }
+ CommandSequence* seq = new CommandSequence();
+ seq->addCommand(new SetInfoCommand("name", filename));
+ if(PARSER_STATE->hasConjecture()) {
+ seq->addCommand(new QueryCommand(MK_CONST(bool(false))));
+ } else {
+ seq->addCommand(new CheckSatCommand());
+ }
+ PARSER_STATE->preemptCommand(seq);
cmd = NULL;
}
;
/* Parse a formula Role */
-formulaRole[CVC4::parser::Tptp::FormulaRole & role]
+formulaRole[CVC4::parser::Tptp::FormulaRole& role]
: LOWER_WORD
{
std::string r = AntlrInput::tokenText($LOWER_WORD);
@@ -204,33 +241,30 @@ formulaRole[CVC4::parser::Tptp::FormulaRole & role]
/* CNF */
/* It can parse a little more than the cnf grammar: false and true can appear.
- Normally only false can appear and only at top level
-*/
+ * Normally only false can appear and only at top level. */
cnfFormula[CVC4::Expr& expr]
- :
- LPAREN_TOK disjunction[expr] RPAREN_TOK
-| disjunction[expr]
+ : LPAREN_TOK cnfDisjunction[expr] RPAREN_TOK
+ | cnfDisjunction[expr]
//| FALSE_TOK { expr = MK_CONST(bool(false)); }
;
-disjunction[CVC4::Expr& expr]
+cnfDisjunction[CVC4::Expr& expr]
@declarations {
std::vector<Expr> args;
}
- :
- literal[expr] {args.push_back(expr); } ( OR_TOK literal[expr] {args.push_back(expr); } )*
- {
- if(args.size() > 1){
- expr = MK_EXPR(kind::OR,args);
+ : cnfLiteral[expr] { args.push_back(expr); }
+ ( OR_TOK cnfLiteral[expr] { args.push_back(expr); } )*
+ { if(args.size() > 1) {
+ expr = MK_EXPR_ASSOCIATIVE(kind::OR, args);
} // else its already in the expr
}
;
-literal[CVC4::Expr& expr]
+cnfLiteral[CVC4::Expr& expr]
: atomicFormula[expr]
- | NOT_TOK atomicFormula[expr] { expr = MK_EXPR(kind::NOT,expr); }
-// | folInfixUnary[expr]
+ | NOT_TOK atomicFormula[expr] { expr = MK_EXPR(kind::NOT, expr); }
+//| folInfixUnary[expr]
;
atomicFormula[CVC4::Expr& expr]
@@ -241,28 +275,32 @@ atomicFormula[CVC4::Expr& expr]
bool equal;
}
: atomicWord[name] (LPAREN_TOK arguments[args] RPAREN_TOK)?
- ( ( equalOp[equal] //equality/disequality between terms
- {
- PARSER_STATE->makeApplication(expr,name,args,true);
- }
- term[expr2]
- {
- expr = MK_EXPR(kind::EQUAL, expr, expr2);
- if(!equal) expr = MK_EXPR(kind::NOT,expr);
- }
- )
- | //predicate
- {
- PARSER_STATE->makeApplication(expr,name,args,false);
+ ( equalOp[equal] term[expr2]
+ { // equality/disequality between terms
+ PARSER_STATE->makeApplication(expr, name, args, true);
+ expr = MK_EXPR(kind::EQUAL, expr, expr2);
+ if(!equal) expr = MK_EXPR(kind::NOT, expr);
}
- )
- | simpleTerm[expr] equalOp[equal] term[expr2]
- {
+ | { // predicate
+ PARSER_STATE->makeApplication(expr, name, args, false);
+ }
+ )
+ | definedFun[expr] LPAREN_TOK arguments[args] RPAREN_TOK
+ equalOp[equal] term[expr2]
+ { expr = EXPR_MANAGER->mkExpr(expr, args);
+ expr = MK_EXPR(kind::EQUAL, expr, expr2);
+ if(!equal) expr = MK_EXPR(kind::NOT, expr);
+ }
+ | (simpleTerm[expr] | letTerm[expr] | conditionalTerm[expr])
+ equalOp[equal] term[expr2]
+ { // equality/disequality between terms
expr = MK_EXPR(kind::EQUAL, expr, expr2);
- if(!equal) expr = MK_EXPR(kind::NOT,expr);
+ if(!equal) expr = MK_EXPR(kind::NOT, expr);
}
+ | definedPred[expr] LPAREN_TOK arguments[args] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(expr, args); }
| definedProp[expr]
-;
+ ;
//%----Using <plain_term> removes a reduce/reduce ambiguity in lex/yacc.
//%----Note: "defined" means a word starting with one $ and "system" means $$.
@@ -270,35 +308,170 @@ definedProp[CVC4::Expr& expr]
: TRUE_TOK { expr = MK_CONST(bool(true)); }
| FALSE_TOK { expr = MK_CONST(bool(false)); }
;
+
+definedPred[CVC4::Expr& expr]
+ : '$less' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::LT); }
+ | '$lesseq' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::LEQ); }
+ | '$greater' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::GT); }
+ | '$greatereq' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::GEQ); }
+ | '$is_rat' // all "real" are actually "rat" in CVC4
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ n = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ expr = MK_EXPR(CVC4::kind::LAMBDA, n, MK_CONST(bool(true)));
+ }
+ | '$is_int' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::IS_INTEGER); }
+ | '$distinct' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::DISTINCT); }
+ ;
+
+definedFun[CVC4::Expr& expr]
+@declarations {
+ bool remainder = false;
+}
+ : '$uminus' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::UMINUS); }
+ | '$sum' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::PLUS); }
+ | '$difference' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::MINUS); }
+ | '$product' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::MULT); }
+ | '$quotient' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::DIVISION_TOTAL); }
+ | ( '$quotient_e' { remainder = false; }
+ | '$remainder_e' { remainder = true; }
+ )
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr d = EXPR_MANAGER->mkBoundVar("D", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n, d);
+ expr = MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, d);
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GEQ, d, MK_CONST(Rational(0))),
+ MK_EXPR(CVC4::kind::TO_INTEGER, expr),
+ MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, expr))));
+ if(remainder) {
+ expr = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::MULT, expr, d));
+ }
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | ( '$quotient_t' { remainder = false; }
+ | '$remainder_t' { remainder = true; }
+ )
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr d = EXPR_MANAGER->mkBoundVar("D", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n, d);
+ expr = MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, d);
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GEQ, expr, MK_CONST(Rational(0))),
+ MK_EXPR(CVC4::kind::TO_INTEGER, expr),
+ MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, expr))));
+ if(remainder) {
+ expr = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::MULT, expr, d));
+ }
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | ( '$quotient_f' { remainder = false; }
+ | '$remainder_f' { remainder = true; }
+ )
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr d = EXPR_MANAGER->mkBoundVar("D", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n, d);
+ expr = MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, d);
+ expr = MK_EXPR(CVC4::kind::TO_INTEGER, expr);
+ if(remainder) {
+ expr = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::MULT, expr, d));
+ }
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$floor' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_INTEGER); }
+ | '$ceiling'
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ expr = MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, n)));
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$truncate'
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GEQ, n, MK_CONST(Rational(0))),
+ MK_EXPR(CVC4::kind::TO_INTEGER, n),
+ MK_EXPR(CVC4::kind::UMINUS, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::UMINUS, n))));
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$round'
+ { Expr n = EXPR_MANAGER->mkBoundVar("N", EXPR_MANAGER->realType());
+ Expr formals = MK_EXPR(CVC4::kind::BOUND_VAR_LIST, n);
+ Expr decPart = MK_EXPR(CVC4::kind::MINUS, n, MK_EXPR(CVC4::kind::TO_INTEGER, n));
+ expr = MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::LT, decPart, MK_CONST(Rational(1, 2))),
+ // if decPart < 0.5, round down
+ MK_EXPR(CVC4::kind::TO_INTEGER, n),
+ MK_EXPR(CVC4::kind::ITE, MK_EXPR(CVC4::kind::GT, decPart, MK_CONST(Rational(1, 2))),
+ // if decPart > 0.5, round up
+ MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::PLUS, n, MK_CONST(Rational(1)))),
+ // if decPart == 0.5, round to nearest even integer:
+ // result is: to_int(n/2 + .5) * 2
+ MK_EXPR(CVC4::kind::MULT, MK_EXPR(CVC4::kind::TO_INTEGER, MK_EXPR(CVC4::kind::PLUS, MK_EXPR(CVC4::kind::DIVISION_TOTAL, n, MK_CONST(Rational(2))), MK_CONST(Rational(1, 2)))), MK_CONST(Rational(2)))));
+ expr = MK_EXPR(CVC4::kind::LAMBDA, formals, expr);
+ }
+ | '$to_int' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_INTEGER); }
+ | '$to_rat' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_REAL); }
+ | '$to_real' { expr = EXPR_MANAGER->operatorOf(CVC4::kind::TO_REAL); }
+ ;
+
//%----Pure CNF should not use $true or $false in problems, and use $false only
//%----at the roots of a refutation.
-equalOp[bool & equal]
- : EQUAL_TOK {equal = true;}
- | DISEQUAL_TOK {equal = false;}
+equalOp[bool& equal]
+ : EQUAL_TOK { equal = true; }
+ | DISEQUAL_TOK { equal = false; }
;
term[CVC4::Expr& expr]
- : functionTerm[expr]
+ : functionTerm[expr]
+ | conditionalTerm[expr]
| simpleTerm[expr]
-// | conditionalTerm
-// | let_term
+ | letTerm[expr]
+ ;
+
+letTerm[CVC4::Expr& expr]
+@declarations {
+ CVC4::Expr lhs, rhs;
+}
+ : '$let_ft' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetFormulaDefn[lhs, rhs] COMMA_TOK
+ term[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
+ | '$let_tt' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetTermDefn[lhs, rhs] COMMA_TOK
+ term[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
;
/* Not an application */
simpleTerm[CVC4::Expr& expr]
: variable[expr]
| NUMBER { expr = PARSER_STATE->d_tmp_expr; }
- | DISTINCT_OBJECT { expr = PARSER_STATE->convertStrToUnsorted(
- AntlrInput::tokenText($DISTINCT_OBJECT)); }
-;
+ | DISTINCT_OBJECT { expr = PARSER_STATE->convertStrToUnsorted(AntlrInput::tokenText($DISTINCT_OBJECT)); }
+ ;
functionTerm[CVC4::Expr& expr]
- : plainTerm[expr] // | <defined_term> | <system_term>
+@declarations {
+ std::vector<CVC4::Expr> args;
+}
+ : plainTerm[expr]
+ | definedFun[expr] LPAREN_TOK arguments[args] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(expr, args); }
+// | <system_term>
+ ;
+
+conditionalTerm[CVC4::Expr& expr]
+@declarations {
+ CVC4::Expr expr2, expr3;
+}
+ : '$ite_t' LPAREN_TOK tffLogicFormula[expr] COMMA_TOK term[expr2] COMMA_TOK term[expr3] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(CVC4::kind::ITE, expr, expr2, expr3); }
;
plainTerm[CVC4::Expr& expr]
-@declarations{
+@declarations {
std::string name;
std::vector<Expr> args;
}
@@ -308,19 +481,19 @@ plainTerm[CVC4::Expr& expr]
}
;
-arguments[std::vector<CVC4::Expr> & args]
-@declarations{
+arguments[std::vector<CVC4::Expr>& args]
+@declarations {
Expr expr;
}
:
term[expr] { args.push_back(expr); } ( COMMA_TOK term[expr] { args.push_back(expr); } )*
;
-variable[CVC4::Expr & expr]
+variable[CVC4::Expr& expr]
: UPPER_WORD
{
std::string name = AntlrInput::tokenText($UPPER_WORD);
- if(!PARSER_STATE->cnf || PARSER_STATE->isDeclared(name)){
+ if(!PARSER_STATE->cnf || PARSER_STATE->isDeclared(name)) {
expr = PARSER_STATE->getVariable(name);
} else {
expr = PARSER_STATE->mkBoundVar(name, PARSER_STATE->d_unsorted);
@@ -331,18 +504,18 @@ variable[CVC4::Expr & expr]
/*******/
/* FOF */
-fofFormula[CVC4::Expr & expr] : fofLogicFormula[expr] ;
+fofFormula[CVC4::Expr& expr] : fofLogicFormula[expr] ;
-fofLogicFormula[CVC4::Expr & expr]
-@declarations{
+fofLogicFormula[CVC4::Expr& expr]
+@declarations {
tptp::NonAssoc na;
std::vector< Expr > args;
Expr expr2;
}
: fofUnitaryFormula[expr]
- ( //Non Assoc <=> <~> ~& ~|
+ ( // Non-associative: <=> <~> ~& ~|
( fofBinaryNonAssoc[na] fofUnitaryFormula[expr2]
- { switch(na){
+ { switch(na) {
case tptp::NA_IFF:
expr = MK_EXPR(kind::IFF,expr,expr2);
break;
@@ -364,21 +537,21 @@ fofLogicFormula[CVC4::Expr & expr]
}
}
)
- | //And &
+ | // N-ary and &
( { args.push_back(expr); }
( AND_TOK fofUnitaryFormula[expr] { args.push_back(expr); } )+
- { expr = MK_EXPR(kind::AND,args); }
+ { expr = MK_EXPR_ASSOCIATIVE(kind::AND, args); }
)
- | //Or |
+ | // N-ary or |
( { args.push_back(expr); }
( OR_TOK fofUnitaryFormula[expr] { args.push_back(expr); } )+
- { expr = MK_EXPR(kind::OR,args); }
+ { expr = MK_EXPR_ASSOCIATIVE(kind::OR, args); }
)
- )?
+ )?
;
-fofUnitaryFormula[CVC4::Expr & expr]
-@declarations{
+fofUnitaryFormula[CVC4::Expr& expr]
+@declarations {
Kind kind;
std::vector< Expr > bv;
}
@@ -389,20 +562,20 @@ fofUnitaryFormula[CVC4::Expr & expr]
folQuantifier[kind] LBRACK_TOK {PARSER_STATE->pushScope();}
( bindvariable[expr] { bv.push_back(expr); }
( COMMA_TOK bindvariable[expr] { bv.push_back(expr); } )* ) RBRACK_TOK
- COLON_TOK fofUnitaryFormula[expr]
- { PARSER_STATE->popScope();
- expr = MK_EXPR(kind, MK_EXPR(kind::BOUND_VAR_LIST, bv), expr);
- } ;
+ COLON_TOK fofUnitaryFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = MK_EXPR(kind, MK_EXPR(kind::BOUND_VAR_LIST, bv), expr);
+ }
+ ;
-bindvariable[CVC4::Expr & expr]
+bindvariable[CVC4::Expr& expr]
: UPPER_WORD
- {
- std::string name = AntlrInput::tokenText($UPPER_WORD);
+ { std::string name = AntlrInput::tokenText($UPPER_WORD);
expr = PARSER_STATE->mkBoundVar(name, PARSER_STATE->d_unsorted);
}
- ;
+ ;
-fofBinaryNonAssoc[CVC4::parser::tptp::NonAssoc & na]
+fofBinaryNonAssoc[CVC4::parser::tptp::NonAssoc& na]
: IFF_TOK { na = tptp::NA_IFF; }
| REVIFF_TOK { na = tptp::NA_REVIFF; }
| REVOR_TOK { na = tptp::NA_REVOR; }
@@ -411,11 +584,229 @@ fofBinaryNonAssoc[CVC4::parser::tptp::NonAssoc & na]
| REVIMPLIES_TOK { na = tptp::NA_REVIMPLIES; }
;
-folQuantifier[CVC4::Kind & kind]
+folQuantifier[CVC4::Kind& kind]
: BANG_TOK { kind = kind::FORALL; }
| MARK_TOK { kind = kind::EXISTS; }
;
+/*******/
+/* TFF */
+tffFormula[CVC4::Expr& expr] : tffLogicFormula[expr];
+
+tffTypedAtom[CVC4::Command*& cmd]
+@declarations {
+ CVC4::Expr expr;
+ CVC4::Type type;
+ std::string name;
+}
+ : LPAREN_TOK tffTypedAtom[cmd] RPAREN_TOK
+ | nameN[name] COLON_TOK
+ ( '$tType'
+ { if(PARSER_STATE->isDeclared(name, SYM_SORT)) {
+ // duplicate declaration is fine, they're compatible
+ cmd = new EmptyCommand("compatible redeclaration of sort " + name);
+ } else if(PARSER_STATE->isDeclared(name, SYM_VARIABLE)) {
+ // error: cannot be both sort and constant
+ PARSER_STATE->parseError("Symbol `" + name + "' previously declared as a constant; cannot also be a sort");
+ } else {
+ // as yet, it's undeclared
+ Type type = PARSER_STATE->mkSort(name);
+ cmd = new DeclareTypeCommand(name, 0, type);
+ }
+ }
+ | parseType[type]
+ { if(PARSER_STATE->isDeclared(name, SYM_SORT)) {
+ // error: cannot be both sort and constant
+ PARSER_STATE->parseError("Symbol `" + name + "' previously declared as a sort");
+ cmd = new EmptyCommand("compatible redeclaration of sort " + name);
+ } else if(PARSER_STATE->isDeclared(name, SYM_VARIABLE)) {
+ if(type == PARSER_STATE->getVariable(name).getType()) {
+ // duplicate declaration is fine, they're compatible
+ cmd = new EmptyCommand("compatible redeclaration of constant " + name);
+ } else {
+ // error: sorts incompatible
+ PARSER_STATE->parseError("Symbol `" + name + "' declared previously with a different sort");
+ }
+ } else {
+ // as yet, it's undeclared
+ CVC4::Expr expr;
+ if(type.isFunction()) {
+ expr = PARSER_STATE->mkFunction(name, type);
+ } else {
+ expr = PARSER_STATE->mkVar(name, type);
+ }
+ cmd = new DeclareFunctionCommand(name, expr, type);
+ }
+ }
+ )
+ ;
+
+tffLogicFormula[CVC4::Expr& expr]
+@declarations {
+ tptp::NonAssoc na;
+ std::vector< Expr > args;
+ Expr expr2;
+}
+ : tffUnitaryFormula[expr]
+ ( // Non Assoc <=> <~> ~& ~|
+ ( fofBinaryNonAssoc[na] tffUnitaryFormula[expr2]
+ { switch(na) {
+ case tptp::NA_IFF:
+ expr = MK_EXPR(kind::IFF,expr,expr2);
+ break;
+ case tptp::NA_REVIFF:
+ expr = MK_EXPR(kind::XOR,expr,expr2);
+ break;
+ case tptp::NA_IMPLIES:
+ expr = MK_EXPR(kind::IMPLIES,expr,expr2);
+ break;
+ case tptp::NA_REVIMPLIES:
+ expr = MK_EXPR(kind::IMPLIES,expr2,expr);
+ break;
+ case tptp::NA_REVOR:
+ expr = MK_EXPR(kind::NOT,MK_EXPR(kind::OR,expr,expr2));
+ break;
+ case tptp::NA_REVAND:
+ expr = MK_EXPR(kind::NOT,MK_EXPR(kind::AND,expr,expr2));
+ break;
+ }
+ }
+ )
+ | // And &
+ ( { args.push_back(expr); }
+ ( AND_TOK tffUnitaryFormula[expr] { args.push_back(expr); } )+
+ { expr = MK_EXPR(kind::AND,args); }
+ )
+ | // Or |
+ ( { args.push_back(expr); }
+ ( OR_TOK tffUnitaryFormula[expr] { args.push_back(expr); } )+
+ { expr = MK_EXPR(kind::OR,args); }
+ )
+ )?
+ ;
+
+tffUnitaryFormula[CVC4::Expr& expr]
+@declarations {
+ Kind kind;
+ std::vector< Expr > bv;
+ Expr lhs, rhs;
+}
+ : atomicFormula[expr]
+ | LPAREN_TOK tffLogicFormula[expr] RPAREN_TOK
+ | NOT_TOK tffUnitaryFormula[expr] { expr = MK_EXPR(kind::NOT,expr); }
+ | // Quantified
+ folQuantifier[kind] LBRACK_TOK {PARSER_STATE->pushScope();}
+ ( tffbindvariable[expr] { bv.push_back(expr); }
+ ( COMMA_TOK tffbindvariable[expr] { bv.push_back(expr); } )* ) RBRACK_TOK
+ COLON_TOK tffUnitaryFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = MK_EXPR(kind, MK_EXPR(kind::BOUND_VAR_LIST, bv), expr);
+ }
+ | '$ite_f' LPAREN_TOK tffLogicFormula[expr] COMMA_TOK tffLogicFormula[lhs] COMMA_TOK tffLogicFormula[rhs] RPAREN_TOK
+ { expr = EXPR_MANAGER->mkExpr(CVC4::kind::ITE, expr, lhs, rhs); }
+ | '$let_tf' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetTermDefn[lhs, rhs] COMMA_TOK
+ tffFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
+ | '$let_ff' LPAREN_TOK { PARSER_STATE->pushScope(); }
+ tffLetFormulaDefn[lhs, rhs] COMMA_TOK
+ tffFormula[expr]
+ { PARSER_STATE->popScope();
+ expr = expr.substitute(lhs, rhs);
+ }
+ RPAREN_TOK
+ ;
+
+tffLetTermDefn[CVC4::Expr& lhs, CVC4::Expr& rhs]
+@declarations {
+ std::vector<CVC4::Expr> bvlist;
+}
+ : (BANG_TOK LBRACK_TOK tffVariableList[bvlist] RBRACK_TOK COLON_TOK)*
+ tffLetTermBinding[bvlist, lhs, rhs]
+ ;
+
+tffLetTermBinding[std::vector<CVC4::Expr>& bvlist, CVC4::Expr& lhs, CVC4::Expr& rhs]
+ : term[lhs] EQUAL_TOK term[rhs]
+ { PARSER_STATE->checkLetBinding(bvlist, lhs, rhs, false);
+ rhs = MK_EXPR(CVC4::kind::LAMBDA, MK_EXPR(CVC4::kind::BOUND_VAR_LIST, lhs.getChildren()), rhs);
+ lhs = lhs.getOperator();
+ }
+ | LPAREN_TOK tffLetTermBinding[bvlist, lhs, rhs] RPAREN_TOK
+ ;
+
+tffLetFormulaDefn[CVC4::Expr& lhs, CVC4::Expr& rhs]
+@declarations {
+ std::vector<CVC4::Expr> bvlist;
+}
+ : (BANG_TOK LBRACK_TOK tffVariableList[bvlist] RBRACK_TOK COLON_TOK)*
+ tffLetFormulaBinding[bvlist, lhs, rhs]
+ ;
+
+tffLetFormulaBinding[std::vector<CVC4::Expr>& bvlist, CVC4::Expr& lhs, CVC4::Expr& rhs]
+ : atomicFormula[lhs] IFF_TOK tffUnitaryFormula[rhs]
+ { PARSER_STATE->checkLetBinding(bvlist, lhs, rhs, true);
+ rhs = MK_EXPR(CVC4::kind::LAMBDA, MK_EXPR(CVC4::kind::BOUND_VAR_LIST, lhs.getChildren()), rhs);
+ lhs = lhs.getOperator();
+ }
+ | LPAREN_TOK tffLetFormulaBinding[bvlist, lhs, rhs] RPAREN_TOK
+ ;
+
+tffbindvariable[CVC4::Expr& expr]
+@declarations {
+ CVC4::Type type = PARSER_STATE->d_unsorted;
+}
+ : UPPER_WORD
+ ( COLON_TOK parseType[type] )?
+ { std::string name = AntlrInput::tokenText($UPPER_WORD);
+ expr = PARSER_STATE->mkBoundVar(name, type);
+ }
+ ;
+
+// bvlist is accumulative; it can already contain elements
+// on the way in, which are left undisturbed
+tffVariableList[std::vector<CVC4::Expr>& bvlist]
+@declarations {
+ CVC4::Expr e;
+}
+ : tffbindvariable[e] { bvlist.push_back(e); }
+ ( COMMA_TOK tffbindvariable[e] { bvlist.push_back(e); } )*
+ ;
+
+parseType[CVC4::Type& type]
+@declarations {
+ std::vector<CVC4::Type> v;
+}
+ : simpleType[type]
+ | ( simpleType[type] { v.push_back(type); }
+ | LPAREN_TOK simpleType[type] { v.push_back(type); }
+ ( TIMES_TOK simpleType[type] { v.push_back(type); } )+
+ RPAREN_TOK
+ )
+ GREATER_TOK simpleType[type]
+ { v.push_back(type);
+ type = EXPR_MANAGER->mkFunctionType(v);
+ }
+ ;
+
+// non-function types
+simpleType[CVC4::Type& type]
+ : DEFINED_SYMBOL
+ { std::string s = AntlrInput::tokenText($DEFINED_SYMBOL);
+ if(s == "\$i") type = PARSER_STATE->d_unsorted;
+ else if(s == "\$o") type = EXPR_MANAGER->booleanType();
+ else if(s == "\$int") type = EXPR_MANAGER->integerType();
+ else if(s == "\$rat") type = EXPR_MANAGER->realType();
+ else if(s == "\$real") type = EXPR_MANAGER->realType();
+ else if(s == "\$tType") PARSER_STATE->parseError("Type of types `\$tType' cannot be used here");
+ else PARSER_STATE->parseError("unknown defined type `" + s + "'");
+ }
+ | LOWER_WORD
+ { type = PARSER_STATE->getSort(AntlrInput::tokenText($LOWER_WORD)); }
+ ;
+
/***********************************************/
/* Anything well parenthesis */
@@ -447,6 +838,7 @@ anything
| FOF_TOK
| THF_TOK
| TFF_TOK
+ | TYPE_TOK
| INCLUDE_TOK
| DISTINCT_OBJECT
| UPPER_WORD
@@ -467,6 +859,8 @@ LBRACK_TOK : '[';
RBRACK_TOK : ']';
COLON_TOK : ':';
+GREATER_TOK : '>';
+
//operator
OR_TOK : '|';
NOT_TOK : '~';
@@ -494,6 +888,7 @@ CNF_TOK : 'cnf';
FOF_TOK : 'fof';
THF_TOK : 'thf';
TFF_TOK : 'tff';
+TYPE_TOK : 'type';
INCLUDE_TOK : 'include';
//Other defined symbols, must be defined after all the other
@@ -533,30 +928,30 @@ UPPER_WORD : UPPER_ALPHA ALPHA_NUMERIC*;
LOWER_WORD : LOWER_ALPHA ALPHA_NUMERIC*;
/* filename */
-unquotedFileName[std::string & name] /* Beware fileName identifier is used by the backend ... */
+unquotedFileName[std::string& name] /* Beware fileName identifier is used by the backend ... */
: (s=LOWER_WORD_SINGLE_QUOTED | s=SINGLE_QUOTED)
{ name = AntlrInput::tokenText($s);
name = name.substr(1, name.size() - 2 );
};
/* axiom name */
-nameN[std::string & name]
+nameN[std::string& name]
: atomicWord[name]
| NUMBER { name = AntlrInput::tokenText($NUMBER); }
;
/* atomic word everything (fof, cnf, thf, tff, include must not be keyword at this position ) */
-atomicWord[std::string & name]
+atomicWord[std::string& name]
: FOF_TOK { name = "fof"; }
| CNF_TOK { name = "cnf"; }
| THF_TOK { name = "thf"; }
| TFF_TOK { name = "tff"; }
+ | TYPE_TOK { name = "type"; }
| INCLUDE_TOK { name = "include"; }
| LOWER_WORD { name = AntlrInput::tokenText($LOWER_WORD); }
- | LOWER_WORD_SINGLE_QUOTED //the lower word single quoted are considered without quote
- {
- /* strip off the quotes */
- name = AntlrInput::tokenTextSubstr($LOWER_WORD_SINGLE_QUOTED,1,
+ | LOWER_WORD_SINGLE_QUOTED // the lower word single quoted are considered without quote
+ { /* strip off the quotes */
+ name = AntlrInput::tokenTextSubstr($LOWER_WORD_SINGLE_QUOTED, 1 ,
($LOWER_WORD_SINGLE_QUOTED->stop - $LOWER_WORD_SINGLE_QUOTED->start) - 1);
}
| SINGLE_QUOTED {name = AntlrInput::tokenText($SINGLE_QUOTED); }; //for the others the quote remains
@@ -565,35 +960,34 @@ atomicWord[std::string & name]
/* Rational */
fragment DOT : '.';
-fragment EXPONENT : 'E'|'e';
+fragment EXPONENT : 'E' | 'e';
fragment SLASH : '/';
fragment DECIMAL : NUMERIC+;
-/* Currently we put all in the rationnal type */
-fragment SIGN[bool & pos] : PLUS_TOK | MINUS_TOK { pos = false; } ;
-
+/* Currently we put all in the rational type */
+fragment SIGN[bool& pos]
+ : PLUS_TOK { pos = true; }
+ | MINUS_TOK { pos = false; }
+ ;
NUMBER
-@declarations{
+@declarations {
bool pos = true;
bool posE = true;
}
- :
- ( SIGN[pos]? num=DECIMAL
- {
- Integer i (AntlrInput::tokenText($num));
- Rational r = ( pos ? i : -i );
- PARSER_STATE->d_tmp_expr = MK_CONST(r);
- }
- | SIGN[pos]? num=DECIMAL DOT den=DECIMAL (EXPONENT SIGN[posE]? e=DECIMAL)?
- {
- std::string snum = AntlrInput::tokenText($num);
+ : ( SIGN[pos]? num=DECIMAL
+ { Integer i(AntlrInput::tokenText($num));
+ Rational r = pos ? i : -i;
+ PARSER_STATE->d_tmp_expr = MK_CONST(r);
+ }
+ | SIGN[pos]? num=DECIMAL DOT den=DECIMAL (EXPONENT SIGN[posE]? e=DECIMAL)?
+ { std::string snum = AntlrInput::tokenText($num);
std::string sden = AntlrInput::tokenText($den);
/* compute the numerator */
- Integer inum( snum + sden );
+ Integer inum(snum + sden);
// The sign
- inum = pos ? inum : - inum;
+ inum = pos ? inum : -inum;
// The exponent
size_t exp = ($e == NULL ? 0 : AntlrInput::tokenToUnsigned($e));
// Decimal part
@@ -601,26 +995,25 @@ NUMBER
/* multiply it by 10 raised to the exponent reduced by the
* number of decimal place in den (dec) */
Rational r;
- if( !posE ) r = Rational(inum, Integer(10).pow(exp + dec));
- else if( exp == dec ) r = Rational(inum);
- else if( exp > dec ) r = Rational(inum * Integer(10).pow(exp - dec));
+ if(!posE) r = Rational(inum, Integer(10).pow(exp + dec));
+ else if(exp == dec) r = Rational(inum);
+ else if(exp > dec) r = Rational(inum * Integer(10).pow(exp - dec));
else r = Rational(inum, Integer(10).pow(dec - exp));
- PARSER_STATE->d_tmp_expr = MK_CONST( r );
+ PARSER_STATE->d_tmp_expr = MK_CONST(r);
+ }
+ | SIGN[pos]? num=DECIMAL SLASH den=DECIMAL
+ { Integer inum(AntlrInput::tokenText($num));
+ Integer iden(AntlrInput::tokenText($den));
+ PARSER_STATE->d_tmp_expr = MK_CONST(Rational(pos ? inum : -inum, iden));
+ }
+ )
+ { if(PARSER_STATE->cnf || PARSER_STATE->fof) {
+ // We're in an unsorted context, so put a conversion around it
+ PARSER_STATE->d_tmp_expr = PARSER_STATE->convertRatToUnsorted( PARSER_STATE->d_tmp_expr );
}
- | SIGN[pos]? num=DECIMAL SLASH den=DECIMAL
- {
- Integer inum(AntlrInput::tokenText($num));
- Integer iden(AntlrInput::tokenText($den));
- PARSER_STATE->d_tmp_expr = MK_CONST(
- Rational(pos ? inum : -inum, iden));
- }
- ) {
- //Put a convertion around it
- PARSER_STATE->d_tmp_expr = PARSER_STATE->convertRatToUnsorted( PARSER_STATE->d_tmp_expr );
}
;
-
/**
* Matches the comments and ignores them
*/
@@ -629,5 +1022,3 @@ COMMENT
| '/*' ( options {greedy=false;} : . )* '*/' { SKIP(); } //comment block
;
-
-
diff --git a/src/parser/tptp/tptp.cpp b/src/parser/tptp/tptp.cpp
index ee7ee4c61..edffaa01f 100644
--- a/src/parser/tptp/tptp.cpp
+++ b/src/parser/tptp/tptp.cpp
@@ -33,25 +33,26 @@ Tptp::Tptp(ExprManager* exprManager, Input* input, bool strictMode, bool parseOn
/* Try to find TPTP dir */
// From tptp4x FileUtilities
//----Try the TPTP directory, and TPTP variations
- char* home = getenv("TPTP");
- if (home == NULL) {
- home = getenv("TPTP_HOME");
+ char* home = getenv("TPTP");
+ if(home == NULL) {
+ home = getenv("TPTP_HOME");
// //----If no TPTP_HOME, try the tptp user (aaargh)
-// if (home == NULL && (PasswdEntry = getpwnam("tptp")) != NULL) {
-// home = PasswdEntry->pw_dir;
+// if(home == NULL && (PasswdEntry = getpwnam("tptp")) != NULL) {
+// home = PasswdEntry->pw_dir;
// }
//----Now look in the TPTP directory from there
- if (home != NULL) {
- d_tptpDir = home;
- d_tptpDir.append("/TPTP/");
- }
- } else {
+ if(home != NULL) {
d_tptpDir = home;
- //add trailing "/"
- if( d_tptpDir[d_tptpDir.size() - 1] != '/'){
- d_tptpDir.append("/");
- }
+ d_tptpDir.append("/TPTP/");
}
+ } else {
+ d_tptpDir = home;
+ //add trailing "/"
+ if(d_tptpDir[d_tptpDir.size() - 1] != '/') {
+ d_tptpDir.append("/");
+ }
+ }
+ d_hasConjecture = false;
}
void Tptp::addTheory(Theory theory) {
@@ -91,7 +92,7 @@ void Tptp::addTheory(Theory theory) {
/* The include are managed in the lexer but called in the parser */
// Inspired by http://www.antlr3.org/api/C/interop.html
-bool newInputStream(std::string fileName, pANTLR3_LEXER lexer){
+bool newInputStream(std::string fileName, pANTLR3_LEXER lexer) {
Debug("parser") << "Including " << fileName << std::endl;
// Create a new input stream and take advantage of built in stream stacking
// in C target runtime.
@@ -102,11 +103,11 @@ bool newInputStream(std::string fileName, pANTLR3_LEXER lexer){
#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
in = antlr3FileStreamNew((pANTLR3_UINT8) fileName.c_str(), ANTLR3_ENC_8BIT);
#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
- if( in == NULL ) {
+ if(in == NULL) {
Debug("parser") << "Can't open " << fileName << std::endl;
return false;
}
- // Samething than the predefined PUSHSTREAM(in);
+ // Same thing as the predefined PUSHSTREAM(in);
lexer->pushCharStream(lexer,in);
// restart it
//lexer->rec->state->tokenStartCharIndex = -10;
@@ -125,41 +126,95 @@ bool newInputStream(std::string fileName, pANTLR3_LEXER lexer){
return true;
}
+/* overridden popCharStream for the lexer - necessary if we had symbol
+ * filtering in file inclusion.
+void Tptp::myPopCharStream(pANTLR3_LEXER lexer) {
+ ((Tptp*)lexer->super)->d_oldPopCharStream(lexer);
+ ((Tptp*)lexer->super)->popScope();
+}
+*/
+
+void Tptp::includeFile(std::string fileName) {
+ // security for online version
+ if(!canIncludeFile()) {
+ parseError("include-file feature was disabled for this run.");
+ }
-void Tptp::includeFile(std::string fileName){
// Get the lexer
AntlrInput * ai = static_cast<AntlrInput *>(getInput());
pANTLR3_LEXER lexer = ai->getAntlr3Lexer();
+
+ // set up popCharStream - would be necessary for handling symbol
+ // filtering in inclusions
+ /*
+ if(d_oldPopCharStream == NULL) {
+ d_oldPopCharStream = lexer->popCharStream;
+ lexer->popCharStream = myPopCharStream;
+ }
+ */
+
+ // push the inclusion scope; will be popped by our special popCharStream
+ // would be necessary for handling symbol filtering in inclusions
+ //pushScope();
+
// get the name of the current stream "Does it work inside an include?"
const std::string inputName = ai->getInputStreamName();
// Test in the directory of the actual parsed file
std::string currentDirFileName;
- if( inputName != "<stdin>"){
- // TODO: Use dirname ot Boost::filesystem?
+ if(inputName != "<stdin>") {
+ // TODO: Use dirname or Boost::filesystem?
size_t pos = inputName.rfind('/');
- if( pos != std::string::npos){
+ if(pos != std::string::npos) {
currentDirFileName = std::string(inputName, 0, pos + 1);
}
currentDirFileName.append(fileName);
- if( newInputStream(currentDirFileName,lexer) ){
+ if(newInputStream(currentDirFileName,lexer)) {
return;
}
} else {
currentDirFileName = "<unknown current directory for stdin>";
}
- if( d_tptpDir.empty() ){
+ if(d_tptpDir.empty()) {
parseError("Couldn't open included file: " + fileName
+ " at " + currentDirFileName + " and the TPTP directory is not specified (environment variable TPTP)");
};
std::string tptpDirFileName = d_tptpDir + fileName;
- if( !newInputStream(tptpDirFileName,lexer) ){
+ if(! newInputStream(tptpDirFileName,lexer)) {
parseError("Couldn't open included file: " + fileName
+ " at " + currentDirFileName + " or " + tptpDirFileName);
}
}
+void Tptp::checkLetBinding(std::vector<Expr>& bvlist, Expr lhs, Expr rhs, bool formula) {
+ if(lhs.getKind() != CVC4::kind::APPLY_UF) {
+ parseError("malformed let: LHS must be a flat function application");
+ }
+ std::vector<CVC4::Expr> v = lhs.getChildren();
+ if(formula && !lhs.getType().isBoolean()) {
+ parseError("malformed let: LHS must be formula");
+ }
+ for(size_t i = 0; i < v.size(); ++i) {
+ if(v[i].hasOperator()) {
+ parseError("malformed let: LHS must be flat, illegal child: " + v[i].toString());
+ }
+ }
+ std::sort(v.begin(), v.end());
+ std::sort(bvlist.begin(), bvlist.end());
+ // ensure all let-bound variables appear on the LHS, and appear only once
+ for(size_t i = 0; i < bvlist.size(); ++i) {
+ std::vector<CVC4::Expr>::const_iterator found = std::lower_bound(v.begin(), v.end(), bvlist[i]);
+ if(found == v.end() || *found != bvlist[i]) {
+ parseError("malformed let: LHS must make use of all quantified variables, missing `" + bvlist[i].toString() + "'");
+ }
+ std::vector<CVC4::Expr>::const_iterator found2 = found + 1;
+ if(found2 != v.end() && *found2 == *found) {
+ parseError("malformed let: LHS cannot use same bound variable twice: " + (*found).toString());
+ }
+ }
+}
+
}/* CVC4::parser namespace */
}/* CVC4 namespace */
diff --git a/src/parser/tptp/tptp.h b/src/parser/tptp/tptp.h
index 6b7adbbf7..e180d1524 100644
--- a/src/parser/tptp/tptp.h
+++ b/src/parser/tptp/tptp.h
@@ -24,6 +24,8 @@
#include "util/hash.h"
#include <ext/hash_set>
#include <cassert>
+#include "parser/options.h"
+#include "parser/antlr_input.h"
namespace CVC4 {
@@ -45,46 +47,57 @@ class Tptp : public Parser {
std::hash_set<Expr, ExprHashFunction> d_r_converted;
std::hash_map<std::string, Expr, StringHashFunction> d_distinct_objects;
- //TPTP directory where to find includes
+ // TPTP directory where to find includes;
// empty if none could be determined
std::string d_tptpDir;
+ // hack to make output SZS ontology-compliant
+ bool d_hasConjecture;
+
+ static void myPopCharStream(pANTLR3_LEXER lexer);
+ void (*d_oldPopCharStream)(pANTLR3_LEXER);
+
public:
- bool cnf; //in a cnf formula
- void addFreeVar(Expr var){assert(cnf); d_freeVar.push_back(var); };
- std::vector< Expr > getFreeVar(){
+ bool cnf; // in a cnf formula
+ bool fof; // in an fof formula
+
+ void addFreeVar(Expr var) {
+ assert(cnf);
+ d_freeVar.push_back(var);
+ }
+ std::vector< Expr > getFreeVar() {
assert(cnf);
std::vector< Expr > r;
r.swap(d_freeVar);
return r;
}
- inline Expr convertRatToUnsorted(Expr expr){
+ inline Expr convertRatToUnsorted(Expr expr) {
ExprManager * em = getExprManager();
// Create the conversion function If they doesn't exists
- if(d_rtu_op.isNull()){
+ if(d_rtu_op.isNull()) {
Type t;
- //Conversion from rational to unsorted
+ // Conversion from rational to unsorted
t = em->mkFunctionType(em->realType(), d_unsorted);
d_rtu_op = em->mkVar("$$rtu",t);
preemptCommand(new DeclareFunctionCommand("$$rtu", d_rtu_op, t));
- //Conversion from unsorted to rational
+ // Conversion from unsorted to rational
t = em->mkFunctionType(d_unsorted, em->realType());
d_utr_op = em->mkVar("$$utr",t);
- preemptCommand(new DeclareFunctionCommand("$$utur", d_utr_op, t));
+ preemptCommand(new DeclareFunctionCommand("$$utr", d_utr_op, t));
}
// Add the inverse in order to show that over the elements that
// appear in the problem there is a bijection between unsorted and
// rational
Expr ret = em->mkExpr(kind::APPLY_UF,d_rtu_op,expr);
- if ( d_r_converted.find(expr) == d_r_converted.end() ){
+ if(d_r_converted.find(expr) == d_r_converted.end()) {
d_r_converted.insert(expr);
- Expr eq = em->mkExpr(kind::EQUAL,expr,
- em->mkExpr(kind::APPLY_UF,d_utr_op,ret));
+ Expr eq = em->mkExpr(kind::EQUAL, expr,
+ em->mkExpr(kind::APPLY_UF, d_utr_op, ret));
preemptCommand(new AssertCommand(eq));
- };
+ }
return ret;
}
@@ -98,12 +111,13 @@ public:
public:
- //TPTP (CNF and FOF) is unsorted so we define this common type
+ // CNF and FOF are unsorted so we define this common type.
+ // This is also the Type of $i in TFF.
Type d_unsorted;
enum Theory {
THEORY_CORE,
- };
+ };/* enum Theory */
enum FormulaRole {
FR_AXIOM,
@@ -120,8 +134,9 @@ public:
FR_FI_FUNCTORS,
FR_FI_PREDICATES,
FR_TYPE,
- };
+ };/* enum FormulaRole */
+ bool hasConjecture() const { return d_hasConjecture; }
protected:
Tptp(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -134,10 +149,10 @@ public:
*/
void addTheory(Theory theory);
- inline void makeApplication(Expr & expr, std::string & name,
- std::vector<Expr> & args, bool term);
+ inline void makeApplication(Expr& expr, std::string& name,
+ std::vector<Expr>& args, bool term);
- inline Command* makeCommand(FormulaRole fr, Expr & expr);
+ inline Command* makeCommand(FormulaRole fr, Expr& expr, bool cnf);
/** Ugly hack because I don't know how to return an expression from a
token */
@@ -147,41 +162,53 @@ public:
is reused */
void includeFile(std::string fileName);
+ /** Check a TPTP let binding for well-formedness. */
+ void checkLetBinding(std::vector<Expr>& bvlist, Expr lhs, Expr rhs, bool formula);
+
private:
void addArithmeticOperators();
};/* class Tptp */
-inline void Tptp::makeApplication(Expr & expr, std::string & name,
- std::vector<Expr> & args, bool term){
- // We distinguish the symbols according to their arities
- std::stringstream ss;
- ss << name << "_" << args.size();
- name = ss.str();
- if(args.empty()){ // Its a constant
- if(isDeclared(name)){ //already appeared
+inline void Tptp::makeApplication(Expr& expr, std::string& name,
+ std::vector<Expr>& args, bool term) {
+ if(args.empty()) { // Its a constant
+ if(isDeclared(name)) { // already appeared
expr = getVariable(name);
} else {
Type t = term ? d_unsorted : getExprManager()->booleanType();
- expr = mkVar(name,t,true); //levelZero
+ expr = mkVar(name, t, ExprManager::VAR_FLAG_GLOBAL); // levelZero
preemptCommand(new DeclareFunctionCommand(name, expr, t));
}
} else { // Its an application
- if(isDeclared(name)){ //already appeared
+ if(isDeclared(name)) { // already appeared
expr = getVariable(name);
} else {
std::vector<Type> sorts(args.size(), d_unsorted);
Type t = term ? d_unsorted : getExprManager()->booleanType();
t = getExprManager()->mkFunctionType(sorts, t);
- expr = mkVar(name,t,true); //levelZero
+ expr = mkVar(name, t, ExprManager::VAR_FLAG_GLOBAL); // levelZero
preemptCommand(new DeclareFunctionCommand(name, expr, t));
}
+ // args might be rationals, in which case we need to create
+ // distinct constants of the "unsorted" sort to represent them
+ for(size_t i = 0; i < args.size(); ++i) {
+ if(args[i].getType().isReal() && FunctionType(expr.getType()).getArgTypes()[i] == d_unsorted) {
+ args[i] = convertRatToUnsorted(args[i]);
+ }
+ }
expr = getExprManager()->mkExpr(kind::APPLY_UF, expr, args);
}
-};
+}
-inline Command* Tptp::makeCommand(FormulaRole fr, Expr & expr){
- switch(fr){
+inline Command* Tptp::makeCommand(FormulaRole fr, Expr& expr, bool cnf) {
+ // For SZS ontology compliance.
+ // if we're in cnf() though, conjectures don't result in "Theorem" or
+ // "CounterSatisfiable".
+ if(!cnf && (fr == FR_NEGATED_CONJECTURE || fr == FR_CONJECTURE)) {
+ d_hasConjecture = true;
+ }
+ switch(fr) {
case FR_AXIOM:
case FR_HYPOTHESIS:
case FR_DEFINITION:
diff --git a/src/parser/tptp/tptp_input.cpp b/src/parser/tptp/tptp_input.cpp
index 34a620187..bfaeb07c9 100644
--- a/src/parser/tptp/tptp_input.cpp
+++ b/src/parser/tptp/tptp_input.cpp
@@ -28,9 +28,9 @@
namespace CVC4 {
namespace parser {
-/* Use lookahead=1 */
+/* Use lookahead=2 */
TptpInput::TptpInput(AntlrInputStream& inputStream) :
- AntlrInput(inputStream, 1) {
+ AntlrInput(inputStream, 2) {
pANTLR3_INPUT_STREAM input = inputStream.getAntlr3InputStream();
assert( input != NULL );
diff --git a/src/parser/tptp/tptp_input.h b/src/parser/tptp/tptp_input.h
index 19e928e7e..cb2bcd3a3 100644
--- a/src/parser/tptp/tptp_input.h
+++ b/src/parser/tptp/tptp_input.h
@@ -64,7 +64,7 @@ public:
/** Get the language that this Input is reading. */
InputLanguage getLanguage() const throw() {
- return language::input::LANG_SMTLIB_V2;
+ return language::input::LANG_TPTP;
}
protected:
diff --git a/src/printer/Makefile.am b/src/printer/Makefile.am
index fd48b8352..cd938088e 100644
--- a/src/printer/Makefile.am
+++ b/src/printer/Makefile.am
@@ -19,7 +19,9 @@ libprinter_la_SOURCES = \
smt2/smt2_printer.h \
smt2/smt2_printer.cpp \
cvc/cvc_printer.h \
- cvc/cvc_printer.cpp
+ cvc/cvc_printer.cpp \
+ tptp/tptp_printer.h \
+ tptp/tptp_printer.cpp
EXTRA_DIST = \
options_handlers.h
diff --git a/src/printer/ast/ast_printer.cpp b/src/printer/ast/ast_printer.cpp
index 57462c9f7..88c769f26 100644
--- a/src/printer/ast/ast_printer.cpp
+++ b/src/printer/ast/ast_printer.cpp
@@ -185,11 +185,11 @@ void AstPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw
}/* AstPrinter::toStream(CommandStatus*) */
-void AstPrinter::toStream(std::ostream& out, Model& m) const throw() {
+void AstPrinter::toStream(std::ostream& out, const Model& m) const throw() {
out << "Model()";
}
-void AstPrinter::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
+void AstPrinter::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
// shouldn't be called; only the non-Command* version above should be
Unreachable();
}
diff --git a/src/printer/ast/ast_printer.h b/src/printer/ast/ast_printer.h
index c9ee6071d..f09de9d00 100644
--- a/src/printer/ast/ast_printer.h
+++ b/src/printer/ast/ast_printer.h
@@ -29,13 +29,13 @@ namespace ast {
class AstPrinter : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
- void toStream(std::ostream& out, Model& m) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
};/* class AstPrinter */
}/* CVC4::printer::ast namespace */
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 23c4727f3..513ff7276 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -813,8 +813,8 @@ void CvcPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw
}/* CvcPrinter::toStream(CommandStatus*) */
-void CvcPrinter::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
- theory::TheoryModel& tm = (theory::TheoryModel&) m;
+void CvcPrinter::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
+ const theory::TheoryModel& tm = (const theory::TheoryModel&) m;
if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) {
TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() );
if( options::modelUninterpDtEnum() && tn.isSort() &&
diff --git a/src/printer/cvc/cvc_printer.h b/src/printer/cvc/cvc_printer.h
index 49b70b012..15b04488d 100644
--- a/src/printer/cvc/cvc_printer.h
+++ b/src/printer/cvc/cvc_printer.h
@@ -29,7 +29,7 @@ namespace cvc {
class CvcPrinter : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types, bool bracket) const throw();
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp
index 2a10ae451..f9d7c2a38 100644
--- a/src/printer/printer.cpp
+++ b/src/printer/printer.cpp
@@ -20,6 +20,7 @@
#include "printer/smt1/smt1_printer.h"
#include "printer/smt2/smt2_printer.h"
+#include "printer/tptp/tptp_printer.h"
#include "printer/cvc/cvc_printer.h"
#include "printer/ast/ast_printer.h"
@@ -41,8 +42,8 @@ Printer* Printer::makePrinter(OutputLanguage lang) throw() {
case LANG_SMTLIB_V2:
return new printer::smt2::Smt2Printer();
- case LANG_TPTP: //TODO the printer
- return new printer::smt2::Smt2Printer();
+ case LANG_TPTP:
+ return new printer::tptp::TptpPrinter();
case LANG_CVC4:
return new printer::cvc::CvcPrinter();
@@ -125,7 +126,7 @@ void Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
}
}/* Printer::toStream(SExpr) */
-void Printer::toStream(std::ostream& out, Model& m) const throw() {
+void Printer::toStream(std::ostream& out, const Model& m) const throw() {
for(size_t i = 0; i < m.getNumCommands(); ++i) {
toStream(out, m, m.getCommand(i));
}
diff --git a/src/printer/printer.h b/src/printer/printer.h
index 48a041d6a..d3a9201ee 100644
--- a/src/printer/printer.h
+++ b/src/printer/printer.h
@@ -43,7 +43,12 @@ protected:
Printer() throw() {}
/** write model response to command */
- virtual void toStream(std::ostream& out, Model& m, const Command* c) const throw() = 0;
+ virtual void toStream(std::ostream& out, const Model& m, const Command* c) const throw() = 0;
+
+ /** write model response to command using another language printer */
+ void toStreamUsing(OutputLanguage lang, std::ostream& out, const Model& m, const Command* c) const throw() {
+ getPrinter(lang)->toStream(out, m, c);
+ }
public:
/** Get the Printer for a given OutputLanguage */
@@ -79,7 +84,7 @@ public:
virtual void toStream(std::ostream& out, const Result& r) const throw();
/** Write a Model out to a stream with this Printer. */
- virtual void toStream(std::ostream& out, Model& m) const throw();
+ virtual void toStream(std::ostream& out, const Model& m) const throw();
};/* class Printer */
diff --git a/src/printer/smt1/smt1_printer.cpp b/src/printer/smt1/smt1_printer.cpp
index f62709988..c5c491cc0 100644
--- a/src/printer/smt1/smt1_printer.cpp
+++ b/src/printer/smt1/smt1_printer.cpp
@@ -49,11 +49,11 @@ void Smt1Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw()
Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
}/* Smt1Printer::toStream() */
-void Smt1Printer::toStream(std::ostream& out, Model& m) const throw() {
+void Smt1Printer::toStream(std::ostream& out, const Model& m) const throw() {
Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, m);
}
-void Smt1Printer::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
+void Smt1Printer::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
// shouldn't be called; only the non-Command* version above should be
Unreachable();
}
diff --git a/src/printer/smt1/smt1_printer.h b/src/printer/smt1/smt1_printer.h
index 185d23699..9faf76cc0 100644
--- a/src/printer/smt1/smt1_printer.h
+++ b/src/printer/smt1/smt1_printer.h
@@ -28,14 +28,14 @@ namespace printer {
namespace smt1 {
class Smt1Printer : public CVC4::Printer {
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
void toStream(std::ostream& out, const SExpr& sexpr) const throw();
- void toStream(std::ostream& out, Model& m) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
};/* class Smt1Printer */
}/* CVC4::printer::smt1 namespace */
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index c59df6269..756e521a6 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -172,6 +172,12 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
break;
}
+ case kind::STORE_ALL: {
+ ArrayStoreAll asa = n.getConst<ArrayStoreAll>();
+ out << "(__array_store_all__ " << asa.getType() << " " << asa.getExpr() << ")";
+ break;
+ }
+
case kind::SUBRANGE_TYPE: {
const SubrangeBounds& bounds = n.getConst<SubrangeBounds>();
// No way to represent subranges in SMT-LIBv2; this is inspired
@@ -214,7 +220,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
bool stillNeedToPrintParams = true;
// operator
- if(n.getNumChildren() != 0) out << '(';
+ if(n.getNumChildren() != 0 && n.getKind()!=kind::INST_PATTERN_LIST) out << '(';
switch(Kind k = n.getKind()) {
// builtin theory
case kind::APPLY: break;
@@ -241,11 +247,25 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::MULT:
case kind::MINUS:
case kind::UMINUS:
- case kind::DIVISION:
case kind::LT:
case kind::LEQ:
case kind::GT:
- case kind::GEQ: out << smtKindString(k) << " "; break;
+ case kind::GEQ:
+ case kind::DIVISION:
+ case kind::DIVISION_TOTAL:
+ case kind::INTS_DIVISION:
+ case kind::INTS_DIVISION_TOTAL:
+ case kind::INTS_MODULUS:
+ case kind::INTS_MODULUS_TOTAL:
+ case kind::ABS:
+ case kind::IS_INTEGER:
+ case kind::TO_INTEGER:
+ case kind::TO_REAL: out << smtKindString(k) << " "; break;
+
+ case kind::DIVISIBLE:
+ out << "(_ divisible " << n.getOperator().getConst<Divisible>().k << ")";
+ stillNeedToPrintParams = false;
+ break;
// arrays theory
case kind::SELECT:
@@ -284,6 +304,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::BITVECTOR_SLE: out << "bvsle "; break;
case kind::BITVECTOR_SGT: out << "bvsgt "; break;
case kind::BITVECTOR_SGE: out << "bvsge "; break;
+ case kind::BITVECTOR_TO_NAT: out << "bv2nat "; break;
case kind::BITVECTOR_EXTRACT:
case kind::BITVECTOR_REPEAT:
@@ -291,6 +312,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::BITVECTOR_SIGN_EXTEND:
case kind::BITVECTOR_ROTATE_LEFT:
case kind::BITVECTOR_ROTATE_RIGHT:
+ case kind::INT_TO_BITVECTOR:
printBvParameterizedOp(out, n);
out << ' ';
stillNeedToPrintParams = false;
@@ -312,12 +334,29 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
break;
// quantifiers
- case kind::FORALL: out << "forall "; break;
- case kind::EXISTS: out << "exists "; break;
+ case kind::FORALL:
+ case kind::EXISTS:
+ if( k==kind::FORALL ){
+ out << "forall ";
+ }else{
+ out << "exists ";
+ }
+ for( unsigned i=0; i<2; i++) {
+ out << n[i] << " ";
+ if( i==0 && n.getNumChildren()==3 ){
+ out << "(! ";
+ }
+ }
+ if( n.getNumChildren()==3 ){
+ out << n[2];
+ out << ")";
+ }
+ out << ")";
+ return;
+ break;
case kind::BOUND_VAR_LIST:
// the left parenthesis is already printed (before the switch)
- for(TNode::iterator i = n.begin(),
- iend = n.end();
+ for(TNode::iterator i = n.begin(), iend = n.end();
i != iend; ) {
out << '(';
toStream(out, (*i), toDepth < 0 ? toDepth : toDepth - 1, types);
@@ -334,8 +373,13 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
out << ')';
return;
case kind::INST_PATTERN:
+ break;
case kind::INST_PATTERN_LIST:
// TODO user patterns
+ for(unsigned i=0; i<n.getNumChildren(); i++) {
+ out << ":pattern " << n[i];
+ }
+ return;
break;
default:
@@ -399,15 +443,25 @@ static string smtKindString(Kind k) throw() {
case kind::MULT: return "*";
case kind::MINUS: return "-";
case kind::UMINUS: return "-";
- case kind::DIVISION: return "/";
case kind::LT: return "<";
case kind::LEQ: return "<=";
case kind::GT: return ">";
case kind::GEQ: return ">=";
+ case kind::DIVISION:
+ case kind::DIVISION_TOTAL: return "/";
+ case kind::INTS_DIVISION: return "div";
+ case kind::INTS_DIVISION_TOTAL: return "INTS_DIVISION_TOTAL";
+ case kind::INTS_MODULUS: return "mod";
+ case kind::INTS_MODULUS_TOTAL: return "INTS_MODULUS_TOTAL";
+ case kind::ABS: return "abs";
+ case kind::IS_INTEGER: return "is_int";
+ case kind::TO_INTEGER: return "to_int";
+ case kind::TO_REAL: return "to_real";
// arrays theory
case kind::SELECT: return "select";
case kind::STORE: return "store";
+ case kind::STORE_ALL: return "__array_store_all__";
case kind::ARRAY_TYPE: return "Array";
// bv theory
@@ -483,6 +537,10 @@ static void printBvParameterizedOp(std::ostream& out, TNode n) throw() {
out << "rotate_right "
<< n.getOperator().getConst<BitVectorRotateRight>().rotateRightAmount;
break;
+ case kind::INT_TO_BITVECTOR:
+ out << "int2bv "
+ << n.getOperator().getConst<IntToBitVector>().size;
+ break;
default:
out << n.getKind();
}
@@ -504,6 +562,7 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
tryToStream<CheckSatCommand>(out, c) ||
tryToStream<QueryCommand>(out, c) ||
tryToStream<QuitCommand>(out, c) ||
+ tryToStream<DeclarationSequence>(out, c) ||
tryToStream<CommandSequence>(out, c) ||
tryToStream<DeclareFunctionCommand>(out, c) ||
tryToStream<DeclareTypeCommand>(out, c) ||
@@ -554,15 +613,15 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const thro
}/* Smt2Printer::toStream(CommandStatus*) */
-void Smt2Printer::toStream(std::ostream& out, Model& m) const throw() {
+void Smt2Printer::toStream(std::ostream& out, const Model& m) const throw() {
out << "(model" << std::endl;
this->Printer::toStream(out, m);
out << ")" << std::endl;
}
-void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const throw() {
- theory::TheoryModel& tm = (theory::TheoryModel&) m;
+void Smt2Printer::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
+ const theory::TheoryModel& tm = (const theory::TheoryModel&) m;
if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) {
TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() );
if( options::modelUninterpDtEnum() && tn.isSort() &&
@@ -644,7 +703,7 @@ void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const
}
void Smt2Printer::toStream(std::ostream& out, const Result& r) const throw() {
- if (r.getType() == Result::TYPE_SAT && r.isSat() == Result::SAT_UNKNOWN) {
+ if(r.getType() == Result::TYPE_SAT && r.isSat() == Result::SAT_UNKNOWN) {
out << "unknown";
} else {
Printer::toStream(out, r);
@@ -718,15 +777,26 @@ static void toStream(std::ostream& out, const DeclareFunctionCommand* c) throw()
static void toStream(std::ostream& out, const DefineFunctionCommand* c) throw() {
Expr func = c->getFunction();
- const vector<Expr>& formals = c->getFormals();
+ const vector<Expr>* formals = &c->getFormals();
out << "(define-fun " << func << " (";
Type type = func.getType();
+ Expr formula = c->getFormula();
if(type.isFunction()) {
- vector<Expr>::const_iterator i = formals.begin();
+ vector<Expr> f;
+ if(formals->empty()) {
+ const vector<Type>& params = FunctionType(type).getArgTypes();
+ for(vector<Type>::const_iterator j = params.begin(); j != params.end(); ++j) {
+ f.push_back(NodeManager::currentNM()->mkSkolem("a", TypeNode::fromType(*j), "",
+ NodeManager::SKOLEM_NO_NOTIFY).toExpr());
+ }
+ formula = NodeManager::currentNM()->toExprManager()->mkExpr(kind::APPLY_UF, formula, f);
+ formals = &f;
+ }
+ vector<Expr>::const_iterator i = formals->begin();
for(;;) {
out << "(" << (*i) << " " << (*i).getType() << ")";
++i;
- if(i != formals.end()) {
+ if(i != formals->end()) {
out << " ";
} else {
break;
@@ -734,7 +804,6 @@ static void toStream(std::ostream& out, const DefineFunctionCommand* c) throw()
}
type = FunctionType(type).getRangeType();
}
- Expr formula = c->getFormula();
out << ") " << type << " " << formula << ")";
}
diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h
index 76ec39258..871b3823a 100644
--- a/src/printer/smt2/smt2_printer.h
+++ b/src/printer/smt2/smt2_printer.h
@@ -29,8 +29,8 @@ namespace smt2 {
class Smt2Printer : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, Model& m, const Command* c) const throw();
- void toStream(std::ostream& out, Model& m) const throw();
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
diff --git a/src/printer/tptp/tptp_printer.cpp b/src/printer/tptp/tptp_printer.cpp
new file mode 100644
index 000000000..ec2a8758b
--- /dev/null
+++ b/src/printer/tptp/tptp_printer.cpp
@@ -0,0 +1,83 @@
+/********************* */
+/*! \file tptp_printer.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief The pretty-printer interface for the TPTP output language
+ **
+ ** The pretty-printer interface for the TPTP output language.
+ **/
+
+#include "printer/tptp/tptp_printer.h"
+#include "expr/expr.h" // for ExprSetDepth etc..
+#include "util/language.h" // for LANG_AST
+#include "expr/node_manager.h" // for VarNameAttr
+#include "expr/command.h"
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <typeinfo>
+
+using namespace std;
+
+namespace CVC4 {
+namespace printer {
+namespace tptp {
+
+void TptpPrinter::toStream(std::ostream& out, TNode n,
+ int toDepth, bool types, size_t dag) const throw() {
+ n.toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const Command* c,
+ int toDepth, bool types, size_t dag) const throw() {
+ c->toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw() {
+ s->toStream(out, language::output::LANG_SMTLIB_V2);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
+}/* TptpPrinter::toStream() */
+
+void TptpPrinter::toStream(std::ostream& out, const Model& m) const throw() {
+ out << "% SZS output start FiniteModel for " << m.getInputName() << endl;
+ for(size_t i = 0; i < m.getNumCommands(); ++i) {
+ this->Printer::toStreamUsing(language::output::LANG_SMTLIB_V2, out, m, m.getCommand(i));
+ }
+ out << "% SZS output end FiniteModel for " << m.getInputName() << endl;
+}
+
+void TptpPrinter::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
+ // shouldn't be called; only the non-Command* version above should be
+ Unreachable();
+}
+
+void TptpPrinter::toStream(std::ostream& out, const Result& r) const throw() {
+ out << "% SZS status ";
+ if(r.isSat() == Result::SAT) {
+ out << "Satisfiable";
+ } else if(r.isSat() == Result::UNSAT) {
+ out << "Unsatisfiable";
+ } else if(r.isValid() == Result::VALID) {
+ out << "Theorem";
+ } else if(r.isValid() == Result::INVALID) {
+ out << "CounterSatisfiable";
+ } else {
+ out << "GaveUp";
+ }
+ out << " for " << r.getInputName();
+}
+
+}/* CVC4::printer::tptp namespace */
+}/* CVC4::printer namespace */
+}/* CVC4 namespace */
diff --git a/src/printer/tptp/tptp_printer.h b/src/printer/tptp/tptp_printer.h
new file mode 100644
index 000000000..a0f3de62b
--- /dev/null
+++ b/src/printer/tptp/tptp_printer.h
@@ -0,0 +1,46 @@
+/********************* */
+/*! \file tptp_printer.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief The pretty-printer interface for the TPTP output language
+ **
+ ** The pretty-printer interface for the TPTP output language.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PRINTER__TPTP_PRINTER_H
+#define __CVC4__PRINTER__TPTP_PRINTER_H
+
+#include <iostream>
+
+#include "printer/printer.h"
+
+namespace CVC4 {
+namespace printer {
+namespace tptp {
+
+class TptpPrinter : public CVC4::Printer {
+ void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
+public:
+ using CVC4::Printer::toStream;
+ void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const CommandStatus* s) const throw();
+ void toStream(std::ostream& out, const SExpr& sexpr) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
+ void toStream(std::ostream& out, const Result& r) const throw();
+};/* class TptpPrinter */
+
+}/* CVC4::printer::tptp namespace */
+}/* CVC4::printer namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__PRINTER__TPTP_PRINTER_H */
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index d6e493c8d..5f03ef5cf 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -19,8 +19,8 @@
using namespace CVC4::prop;
namespace CVC4 {
+
CnfProof::CnfProof(CnfStream* stream) :
d_cnfStream(stream) {}
-
} /* CVC4 namespace */
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index c265e46df..984dc76c6 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -17,7 +17,7 @@
**/
#include "cvc4_private.h"
-
+#include "util/proof.h"
#ifndef __CVC4__CNF_PROOF_H
#define __CVC4__CNF_PROOF_H
diff --git a/src/proof/sat_proof.cpp b/src/proof/sat_proof.cpp
index df695c2d1..d9b57f87e 100644
--- a/src/proof/sat_proof.cpp
+++ b/src/proof/sat_proof.cpp
@@ -173,7 +173,10 @@ SatProof::SatProof(Minisat::Solver* solver, bool checkRes) :
d_emptyClauseId(-1),
d_nullId(-2),
d_temp_clauseId(),
- d_temp_idClause()
+ d_temp_idClause(),
+ d_unitConflictId(),
+ d_storedUnitConflict(false),
+ d_atomToVar()
{
d_proxy = new ProofProxy(this);
}
@@ -353,6 +356,7 @@ ClauseId SatProof::registerClause(::Minisat::CRef clause, bool isInput) {
d_inputClauses.insert(newId);
}
}
+ Debug("proof:sat:detailed") <<"registerClause " << d_clauseId[clause] << " " <<isInput << "\n";
return d_clauseId[clause];
}
@@ -367,6 +371,7 @@ ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, bool isInput) {
d_inputClauses.insert(newId);
}
}
+ Debug("proof:sat:detailed") <<"registerUnitClause " << d_unitId[toInt(lit)] << " " << isInput <<"\n";
return d_unitId[toInt(lit)];
}
@@ -527,10 +532,25 @@ void SatProof::toStream(std::ostream& out) {
Unimplemented("native proof printing not supported yet");
}
+void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit) {
+ Assert (!d_storedUnitConflict);
+ d_unitConflictId = registerUnitClause(conflict_lit);
+ d_storedUnitConflict = true;
+ Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+}
+
void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
Assert(d_resStack.size() == 0);
- //ClauseId conflict_id = getClauseId(conflict_ref);
- ClauseId conflict_id = registerClause(conflict_ref); //FIXME
+ Assert (conflict_ref != ::Minisat::CRef_Undef);
+ ClauseId conflict_id;
+ if (conflict_ref == ::Minisat::CRef_Lazy) {
+ Assert (d_storedUnitConflict);
+ conflict_id = d_unitConflictId;
+ } else {
+ Assert (!d_storedUnitConflict);
+ conflict_id = registerClause(conflict_ref); //FIXME
+ }
+
Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
print(conflict_id);
@@ -573,6 +593,14 @@ void SatProof::markDeleted(CRef clause) {
}
}
+/// store mapping from theory atoms to new variables
+void SatProof::storeAtom(::Minisat::Lit literal, Expr atom) {
+ Assert(d_atomToVar.find(atom) == d_atomToVar.end());
+ d_atomToVar[atom] = literal;
+}
+
+
+
/// LFSCSatProof class
std::string LFSCSatProof::varName(::Minisat::Lit lit) {
@@ -613,6 +641,7 @@ void LFSCSatProof::collectLemmas(ClauseId id) {
d_seenLemmas.insert(id);
}
+ Assert (d_resChains.find(id) != d_resChains.end());
ResChain* res = d_resChains[id];
ClauseId start = res->getStart();
collectLemmas(start);
@@ -658,6 +687,14 @@ void LFSCSatProof::printResolution(ClauseId id) {
void LFSCSatProof::printInputClause(ClauseId id) {
+ if (isUnit(id)) {
+ ::Minisat::Lit lit = getUnit(id);
+ d_clauseSS << "(% " << clauseName(id) << " (holds (clc ";
+ d_clauseSS << varName(lit) << "cln ))";
+ d_paren << ")";
+ return;
+ }
+
ostringstream os;
CRef ref = getClauseRef(id);
Assert (ref != CRef_Undef);
@@ -692,6 +729,7 @@ void LFSCSatProof::printVariables() {
void LFSCSatProof::flush(std::ostream& out) {
+ out << d_atomsSS.str();
out << "(check \n";
d_paren <<")";
out << d_varSS.str();
@@ -705,7 +743,7 @@ void LFSCSatProof::flush(std::ostream& out) {
void LFSCSatProof::toStream(std::ostream& out) {
Debug("proof:sat") << " LFSCSatProof::printProof \n";
-
+
// first collect lemmas to print in reverse order
collectLemmas(d_emptyClauseId);
for(IdSet::iterator it = d_seenLemmas.begin(); it!= d_seenLemmas.end(); ++it) {
@@ -713,13 +751,22 @@ void LFSCSatProof::toStream(std::ostream& out) {
printResolution(*it);
}
}
+ printAtoms();
// last resolution to be printed is the empty clause
printResolution(d_emptyClauseId);
-
+
printClauses();
printVariables();
flush(out);
}
+void LFSCSatProof::printAtoms() {
+ d_atomsSS << "; Mapping between boolean variables and theory atoms \n";
+ for (AtomToVar::iterator it = d_atomToVar.begin(); it != d_atomToVar.end(); ++it) {
+ d_atomsSS << "; " << it->first << " => v" << var(it->second) << "\n";
+ }
+}
+
+
} /* CVC4 namespace */
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index d497a4eba..fb8966400 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -26,6 +26,8 @@
#include <ext/hash_map>
#include <ext/hash_set>
#include <sstream>
+#include "expr/expr.h"
+
namespace Minisat {
class Solver;
@@ -90,6 +92,8 @@ typedef std::vector < ResChain* > ResStack;
typedef std::hash_set < int > VarSet;
typedef std::set < ClauseId > IdSet;
typedef std::vector < ::Minisat::Lit > LitVector;
+typedef __gnu_cxx::hash_map<Expr, ::Minisat::Lit, ExprHashFunction > AtomToVar;
+
class SatProof;
class ProofProxy : public ProofProxyAbstract {
@@ -124,7 +128,14 @@ protected:
// temporary map for updating CRefs
ClauseIdMap d_temp_clauseId;
- IdClauseMap d_temp_idClause;
+ IdClauseMap d_temp_idClause;
+
+ // unit conflict
+ ClauseId d_unitConflictId;
+ bool d_storedUnitConflict;
+
+ // atom mapping
+ AtomToVar d_atomToVar;
public:
SatProof(::Minisat::Solver* solver, bool checkRes = false);
protected:
@@ -197,6 +208,9 @@ public:
/// clause registration methods
ClauseId registerClause(const ::Minisat::CRef clause, bool isInput = false);
ClauseId registerUnitClause(const ::Minisat::Lit lit, bool isInput = false);
+
+ void storeUnitConflict(::Minisat::Lit lit);
+
/**
* Marks the deleted clauses as deleted. Note we may still use them in the final
* resolution.
@@ -216,12 +230,20 @@ public:
*/
void storeUnitResolution(::Minisat::Lit lit);
- ProofProxy* getProxy() {return d_proxy; }
+ ProofProxy* getProxy() {return d_proxy; }
+ /**
+ * At mapping between literal and theory-atom it represents
+ *
+ * @param literal
+ * @param atom
+ */
+ void storeAtom(::Minisat::Lit literal, Expr atom);
};/* class SatProof */
class LFSCSatProof: public SatProof {
private:
- VarSet d_seenVars;
+ VarSet d_seenVars;
+ std::ostringstream d_atomsSS;
std::ostringstream d_varSS;
std::ostringstream d_lemmaSS;
std::ostringstream d_clauseSS;
@@ -239,11 +261,12 @@ private:
void printVariables();
void printClauses();
void flush(std::ostream& out);
-
+ void printAtoms();
public:
LFSCSatProof(::Minisat::Solver* solver, bool checkRes = false):
SatProof(solver, checkRes),
d_seenVars(),
+ d_atomsSS(),
d_varSS(),
d_lemmaSS(),
d_paren(),
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index 4be58bdef..8ebb461e5 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -27,7 +27,9 @@
#include "expr/expr.h"
#include "prop/theory_proxy.h"
#include "theory/bv/options.h"
-
+#include "proof/proof_manager.h"
+#include "proof/sat_proof.h"
+#include "prop/minisat/minisat.h"
#include <queue>
using namespace std;
@@ -236,7 +238,7 @@ SatLiteral CnfStream::convertAtom(TNode node) {
// Make a new literal (variables are not considered theory literals)
SatLiteral lit = newLiteral(node, theoryLiteral, preRegister, canEliminate);
-
+ PROOF (ProofManager::getSatProof()->storeAtom(MinisatSatSolver::toMinisatLit(lit), node.toExpr()); );
// Return the resulting literal
return lit;
}
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 6196ca357..36e196821 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -135,6 +135,8 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context,
// Assert the constants
uncheckedEnqueue(mkLit(varTrue, false));
uncheckedEnqueue(mkLit(varFalse, true));
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varTrue, false), true); )
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), true); )
}
@@ -229,7 +231,7 @@ CRef Solver::reason(Var x) {
int i, j;
Lit prev = lit_Undef;
for (i = 0, j = 0; i < explanation.size(); ++ i) {
- // This clause is valid theory propagation, so it's level is the level of the top literal
+ // This clause is valid theory propagation, so its level is the level of the top literal
explLevel = std::max(explLevel, intro_level(var(explanation[i])));
Assert(value(explanation[i]) != l_Undef);
@@ -261,6 +263,7 @@ CRef Solver::reason(Var x) {
// Construct the reason
CRef real_reason = ca.alloc(explLevel, explanation, true);
+ PROOF (ProofManager::getSatProof()->registerClause(real_reason, true); );
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -297,9 +300,9 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
if (ps[i] == p) {
continue;
}
- // If a literals is false at 0 level (both sat and user level) we also ignore it
+ // If a literal is false at 0 level (both sat and user level) we also ignore it
if (value(ps[i]) == l_False) {
- if (level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) {
+ if (!PROOF_ON() && level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) {
continue;
} else {
// If we decide to keep it, we count it into the false literals
@@ -345,7 +348,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
PROOF( if (ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], true); } )
- return ok = (propagate(CHECK_WITHOUTH_THEORY) == CRef_Undef);
+ return ok = (propagate(CHECK_WITHOUT_THEORY) == CRef_Undef);
} else return ok;
}
}
@@ -789,7 +792,8 @@ CRef Solver::propagate(TheoryCheckType type)
// If there are lemmas (or conflicts) update them
if (lemmas.size() > 0) {
recheck = true;
- return updateLemmas();
+ confl = updateLemmas();
+ return confl;
} else {
recheck = proxy->theoryNeedCheck();
return confl;
@@ -801,9 +805,8 @@ CRef Solver::propagate(TheoryCheckType type)
do {
// Propagate on the clauses
confl = propagateBool();
-
// If no conflict, do the theory check
- if (confl == CRef_Undef && type != CHECK_WITHOUTH_THEORY) {
+ if (confl == CRef_Undef && type != CHECK_WITHOUT_THEORY) {
// Do the theory check
if (type == CHECK_FINAL_FAKE) {
theoryCheck(CVC4::theory::Theory::EFFORT_FULL);
@@ -836,7 +839,6 @@ CRef Solver::propagate(TheoryCheckType type)
}
}
} while (confl == CRef_Undef && qhead < trail.size());
-
return confl;
}
@@ -1017,8 +1019,8 @@ void Solver::removeClausesAboveLevel(vec<CRef>& cs, int level)
for (i = j = 0; i < cs.size(); i++){
Clause& c = ca[cs[i]];
if (c.level() > level) {
- assert(!locked(c));
- removeClause(cs[i]);
+ assert(!locked(c));
+ removeClause(cs[i]);
} else {
cs[j++] = cs[i];
}
@@ -1048,7 +1050,7 @@ bool Solver::simplify()
{
assert(decisionLevel() == 0);
- if (!ok || propagate(CHECK_WITHOUTH_THEORY) != CRef_Undef)
+ if (!ok || propagate(CHECK_WITHOUT_THEORY) != CRef_Undef)
return ok = false;
if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
@@ -1210,7 +1212,7 @@ lbool Solver::search(int nof_conflicts)
if (next == lit_Undef) {
// We need to do a full theory check to confirm
- Debug("minisat::search") << "Doing a full theoy check..."
+ Debug("minisat::search") << "Doing a full theory check..."
<< std::endl;
check_type = CHECK_FINAL;
continue;
@@ -1490,7 +1492,7 @@ void Solver::pop()
Debug("minisat") << "== unassigning " << trail.last() << std::endl;
Var x = var(trail.last());
if (user_level(x) > assertionLevel) {
- assigns [x] = l_Undef;
+ assigns[x] = l_Undef;
vardata[x] = VarData(CRef_Undef, -1, -1, intro_level(x), -1);
if(phase_saving >= 1 && (polarity[x] & 0x2) == 0)
polarity[x] = sign(trail.last());
@@ -1503,7 +1505,7 @@ void Solver::pop()
// The head should be at the trail top
qhead = trail.size();
- // Remove the clause
+ // Remove the clauses
removeClausesAboveLevel(clauses_persistent, assertionLevel);
removeClausesAboveLevel(clauses_removable, assertionLevel);
@@ -1579,6 +1581,7 @@ CRef Solver::updateLemmas() {
vec<Lit>& lemma = lemmas[i];
// If it's an empty lemma, we have a conflict at zero level
if (lemma.size() == 0) {
+ Assert (! PROOF_ON());
conflict = CRef_Lazy;
backtrackLevel = 0;
Debug("minisat::lemmas") << "Solver::updateLemmas(): found empty clause" << std::endl;
@@ -1628,6 +1631,7 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
+ PROOF (ProofManager::getSatProof()->registerClause(lemma_ref, true); );
if (removable) {
clauses_removable.push(lemma_ref);
} else {
@@ -1647,6 +1651,7 @@ CRef Solver::updateLemmas() {
} else {
Debug("minisat::lemmas") << "Solver::updateLemmas(): unit conflict or empty clause" << std::endl;
conflict = CRef_Lazy;
+ PROOF(ProofManager::getSatProof()->storeUnitConflict(lemma[0]););
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index 55780479a..30d72ac75 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -266,7 +266,7 @@ protected:
int level;
// User level when the literal was added to the trail
int user_level;
- // Use level at which this literal was introduced
+ // User level at which this literal was introduced
int intro_level;
// The index in the trail
int trail_index;
@@ -335,7 +335,7 @@ protected:
enum TheoryCheckType {
// Quick check, but don't perform theory reasoning
- CHECK_WITHOUTH_THEORY,
+ CHECK_WITHOUT_THEORY,
// Check and perform theory reasoning
CHECK_WITH_THEORY,
// The SAT abstraction of the problem is satisfiable, perform a full theory check
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index 37e471846..ec49b5f71 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -30,16 +30,15 @@ class MinisatSatSolver : public DPLLSatSolverInterface {
/** The SatSolver used */
Minisat::SimpSolver* d_minisat;
-
/** The SatSolver uses this to communicate with the theories */
TheoryProxy* d_theoryProxy;
- /** Context we will be using to synchronzie the sat solver */
+ /** Context we will be using to synchronize the sat solver */
context::Context* d_context;
public:
- MinisatSatSolver ();
+ MinisatSatSolver();
~MinisatSatSolver();
static SatVariable toSatVariable(Minisat::Var var);
diff --git a/src/prop/minisat/mtl/Vec.h b/src/prop/minisat/mtl/Vec.h
index 5d8c2850e..5f85f6fcd 100644
--- a/src/prop/minisat/mtl/Vec.h
+++ b/src/prop/minisat/mtl/Vec.h
@@ -86,7 +86,7 @@ public:
const T& operator [] (int index) const { return data[index]; }
T& operator [] (int index) { return data[index]; }
- // Duplicatation (preferred instead):
+ // Duplication (preferred instead):
void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) copy[i] = data[i]; }
void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; }
};
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc
index 0e0e5d3ae..6dcdb76c7 100644
--- a/src/prop/minisat/simp/SimpSolver.cc
+++ b/src/prop/minisat/simp/SimpSolver.cc
@@ -67,7 +67,7 @@ SimpSolver::SimpSolver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* c
if(options::minisatUseElim() &&
options::minisatUseElim.wasSetByUser() &&
enableIncremental) {
- WarningOnce() << "Incremental mode incompatible with --minisat-elimination" << std::endl;
+ WarningOnce() << "Incremental mode incompatible with --minisat-elim" << std::endl;
}
vec<Lit> dummy(1,lit_Undef);
@@ -239,7 +239,7 @@ bool SimpSolver::strengthenClause(CRef cr, Lit l)
updateElimHeap(var(l));
}
- return c.size() == 1 ? enqueue(c[0]) && propagate(CHECK_WITHOUTH_THEORY) == CRef_Undef : true;
+ return c.size() == 1 ? enqueue(c[0]) && propagate(CHECK_WITHOUT_THEORY) == CRef_Undef : true;
}
@@ -346,7 +346,7 @@ bool SimpSolver::implied(const vec<Lit>& c)
uncheckedEnqueue(~c[i]);
}
- bool result = propagate(CHECK_WITHOUTH_THEORY) != CRef_Undef;
+ bool result = propagate(CHECK_WITHOUT_THEORY) != CRef_Undef;
cancelUntil(0);
return result;
}
@@ -435,7 +435,7 @@ bool SimpSolver::asymm(Var v, CRef cr)
else
l = c[i];
- if (propagate(CHECK_WITHOUTH_THEORY) != CRef_Undef){
+ if (propagate(CHECK_WITHOUT_THEORY) != CRef_Undef){
cancelUntil(0);
asymm_lits++;
if (!strengthenClause(cr, l))
diff --git a/src/prop/options b/src/prop/options
index e3a0f814a..b300c3fb6 100644
--- a/src/prop/options
+++ b/src/prop/options
@@ -22,8 +22,8 @@ option satRestartFirst --restart-int-base=N unsigned :default 25
option satRestartInc --restart-int-inc=F double :default 3.0 :predicate greater_equal(0.0)
sets the restart interval increase factor for the sat solver (F=3.0 by default)
-option sat_refine_conflicts --refine-conflicts bool
- refine theory conflict clauses
+option sat_refine_conflicts --refine-conflicts bool :default false
+ refine theory conflict clauses (default false)
option minisatUseElim --minisat-elimination bool :default true :read-write
use Minisat elimination
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index c465ed97a..a169d31e6 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -83,7 +83,8 @@ PropEngine::PropEngine(TheoryEngine* te, DecisionEngine *de, Context* satContext
userContext,
// fullLitToNode Map =
options::threads() > 1 ||
- options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY);
+ options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY
+ );
d_satSolver->initialize(d_context, new TheoryProxy(this, d_theoryEngine, d_decisionEngine, d_context, d_cnfStream));
@@ -280,6 +281,7 @@ void PropEngine::interrupt() throw(ModalException) {
void PropEngine::spendResource() throw() {
// TODO implement me
+ checkTime();
}
bool PropEngine::properExplanation(TNode node, TNode expl) const {
diff --git a/src/smt/boolean_terms.cpp b/src/smt/boolean_terms.cpp
index 0063035ff..9f1b9c1a6 100644
--- a/src/smt/boolean_terms.cpp
+++ b/src/smt/boolean_terms.cpp
@@ -288,7 +288,7 @@ TypeNode BooleanTermConverter::convertType(TypeNode type, bool datatypesContext)
}
return newRec;
}
- if(type.getNumChildren() > 0) {
+ if(!type.isSort() && type.getNumChildren() > 0) {
Debug("boolean-terms") << "here at A for " << type << ":" << type.getId() << endl;
// This should handle tuples and arrays ok.
// Might handle function types too, but they can't go
@@ -487,7 +487,39 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
} else if(t.isArray()) {
TypeNode indexType = convertType(t.getArrayIndexType(), false);
TypeNode constituentType = convertType(t.getArrayConstituentType(), false);
- if(indexType != t.getArrayIndexType() || constituentType != t.getArrayConstituentType()) {
+ if(indexType != t.getArrayIndexType() && constituentType == t.getArrayConstituentType()) {
+ TypeNode newType = nm->mkArrayType(indexType, constituentType);
+ Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()) + "'",
+ newType, "an array variable introduced by Boolean-term conversion",
+ NodeManager::SKOLEM_EXACT_NAME);
+ top.setAttribute(BooleanTermAttr(), n);
+ Debug("boolean-terms") << "constructed: " << n << " of type " << newType << endl;
+ Node n_ff = nm->mkNode(kind::SELECT, n, d_ff);
+ Node n_tt = nm->mkNode(kind::SELECT, n, d_tt);
+ Node base = nm->mkConst(ArrayStoreAll(ArrayType(top.getType().toType()), (*TypeEnumerator(n_ff.getType())).toExpr()));
+ Node repl = nm->mkNode(kind::STORE,
+ nm->mkNode(kind::STORE, base, nm->mkConst(true),
+ n_tt),
+ nm->mkConst(false), n_ff);
+ Debug("boolean-terms") << "array replacement: " << top << " => " << repl << endl;
+ d_smt.d_theoryEngine->getModel()->addSubstitution(top, repl);
+ d_termCache[make_pair(top, parentTheory)] = n;
+ result.top() << n;
+ worklist.pop();
+ goto next_worklist;
+ } else if(indexType == t.getArrayIndexType() && constituentType != t.getArrayConstituentType()) {
+ TypeNode newType = nm->mkArrayType(indexType, constituentType);
+ Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()) + "'",
+ newType, "an array variable introduced by Boolean-term conversion",
+ NodeManager::SKOLEM_EXACT_NAME);
+ top.setAttribute(BooleanTermAttr(), n);
+ Debug("boolean-terms") << "constructed: " << n << " of type " << newType << endl;
+ d_smt.d_theoryEngine->getModel()->addSubstitution(top, n);
+ d_termCache[make_pair(top, parentTheory)] = n;
+ result.top() << n;
+ worklist.pop();
+ goto next_worklist;
+ } else if(indexType != t.getArrayIndexType() && constituentType != t.getArrayConstituentType()) {
TypeNode newType = nm->mkArrayType(indexType, constituentType);
Node n = nm->mkSkolem(top.getAttribute(expr::VarNameAttr()) + "'",
newType, "an array variable introduced by Boolean-term conversion",
@@ -594,7 +626,7 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
worklist.pop();
goto next_worklist;
}
- } else if(t.getNumChildren() > 0) {
+ } else if(!t.isSort() && t.getNumChildren() > 0) {
for(TypeNode::iterator i = t.begin(); i != t.end(); ++i) {
if((*i).isBoolean()) {
vector<TypeNode> argTypes(t.begin(), t.end());
@@ -617,9 +649,6 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
goto next_worklist;
}
switch(k) {
- case kind::LAMBDA:
- Unreachable("not expecting a LAMBDA in boolean-term conversion: %s", top.toString().c_str());
-
case kind::BOUND_VAR_LIST:
result.top() << top;
worklist.pop();
@@ -704,7 +733,8 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
k != kind::TUPLE_SELECT &&
k != kind::TUPLE_UPDATE &&
k != kind::RECORD_SELECT &&
- k != kind::RECORD_UPDATE) {
+ k != kind::RECORD_UPDATE &&
+ k != kind::DIVISIBLE) {
Debug("bt") << "rewriting: " << top.getOperator() << endl;
result.top() << rewriteBooleanTermsRec(top.getOperator(), theory::THEORY_BUILTIN, quantBoolVars);
Debug("bt") << "got: " << result.top().getOperator() << endl;
@@ -715,7 +745,7 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
// push children
for(int i = top.getNumChildren() - 1; i >= 0; --i) {
Debug("bt") << "rewriting: " << top[i] << endl;
- worklist.push(triple<TNode, theory::TheoryId, bool>(top[i], isBoolean(top, i) ? theory::THEORY_BOOL : (top.getKind() == kind::APPLY_CONSTRUCTOR ? theory::THEORY_DATATYPES : theory::THEORY_BUILTIN), false));
+ worklist.push(triple<TNode, theory::TheoryId, bool>(top[i], top.getKind() == kind::CHAIN ? parentTheory : (isBoolean(top, i) ? theory::THEORY_BOOL : (top.getKind() == kind::APPLY_CONSTRUCTOR ? theory::THEORY_DATATYPES : theory::THEORY_BUILTIN)), false));
//b << rewriteBooleanTermsRec(top[i], isBoolean(top, i) ? , quantBoolVars);
//Debug("bt") << "got: " << b[b.getNumChildren() - 1] << endl;
}
diff --git a/src/smt/options b/src/smt/options
index 2680f4105..7a72881b4 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -24,6 +24,8 @@ common-option produceModels produce-models -m --produce-models bool :default fal
support the get-value and get-model commands
option checkModels check-models --check-models bool :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
after SAT/INVALID/UNKNOWN, check that the generated model satisfies user assertions
+option dumpModels --dump-models bool :default false
+ output models after every SAT/INVALID/UNKNOWN response
option proof produce-proofs --proof bool :default false :predicate CVC4::smt::proofEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
turn on proof generation
# this is just a placeholder for later; it doesn't show up in command-line options listings
@@ -46,7 +48,7 @@ option unconstrainedSimp --unconstrained-simp bool :default false :read-write
option repeatSimp --repeat-simp bool :read-write
make multiple passes with nonclausal simplifier
-option sortInference --sort-inference bool :default false
+option sortInference --sort-inference bool :read-write :default false
apply sort inference to input problem
common-option incrementalSolving incremental -i --incremental bool
@@ -67,7 +69,7 @@ common-option cumulativeMillisecondLimit tlimit --tlimit=MS "unsigned long"
common-option perCallMillisecondLimit tlimit-per --tlimit-per=MS "unsigned long"
enable time limiting per query (give milliseconds)
common-option cumulativeResourceLimit rlimit --rlimit=N "unsigned long"
- enable resource limiting
+ enable resource limiting (currently, roughly the number of SAT conflicts)
common-option perCallResourceLimit rlimit-per --rlimit-per=N "unsigned long"
enable resource limiting per query
diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h
index 6b8d94c08..c631b8c84 100644
--- a/src/smt/options_handlers.h
+++ b/src/smt/options_handlers.h
@@ -186,6 +186,11 @@ inline void dumpMode(std::string option, std::string optarg, SmtEngine* smt) {
} else if(!strcmp(p, "ite-removal")) {
} else if(!strcmp(p, "repeat-simplify")) {
} else if(!strcmp(p, "theory-preprocessing")) {
+ } else if(!strcmp(p, "nonclausal")) {
+ } else if(!strcmp(p, "theorypp")) {
+ } else if(!strcmp(p, "itesimp")) {
+ } else if(!strcmp(p, "unconstrained")) {
+ } else if(!strcmp(p, "repeatsimp")) {
} else {
throw OptionException(std::string("don't know how to dump `") +
optargPtr + "'. Please consult --dump help.");
@@ -409,6 +414,17 @@ inline std::ostream* checkReplayLogFilename(std::string option, std::string opta
#endif /* CVC4_REPLAY */
}
+// ensure we are a stats-enabled build of CVC4
+inline void statsEnabledBuild(std::string option, bool value, SmtEngine* smt) throw(OptionException) {
+#ifndef CVC4_STATISTICS_ON
+ if(value) {
+ std::stringstream ss;
+ ss << "option `" << option << "' requires a statistics-enabled build of CVC4; this binary was not built with statistics support";
+ throw OptionException(ss.str());
+ }
+#endif /* CVC4_STATISTICS_ON */
+}
+
}/* CVC4::smt namespace */
}/* CVC4 namespace */
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 0d473a1a1..39ccc70c4 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -74,6 +74,8 @@
#include "util/sort_inference.h"
#include "theory/quantifiers/macros.h"
#include "theory/datatypes/options.h"
+#include "theory/quantifiers/first_order_reasoning.h"
+#include "theory/strings/theory_strings_preprocess.h"
using namespace std;
using namespace CVC4;
@@ -245,6 +247,15 @@ class SmtEnginePrivate : public NodeManagerListener {
/** Assertions to push to sat */
vector<Node> d_assertionsToCheck;
+ /** Whether any assertions have been processed */
+ CDO<bool> d_assertionsProcessed;
+
+ /** Index for where to store substitutions */
+ CDO<unsigned> d_substitutionsIndex;
+
+ // Cached true value
+ Node d_true;
+
/**
* A context that never pushes/pops, for use by CD structures (like
* SubstitutionMaps) that should be "global".
@@ -292,14 +303,13 @@ class SmtEnginePrivate : public NodeManagerListener {
*/
Node d_modZero;
+public:
/**
* Map from skolem variables to index in d_assertionsToCheck containing
* corresponding introduced Boolean ite
*/
IteSkolemMap d_iteSkolemMap;
-public:
-
/** Instance of the ITE remover */
RemoveITE d_iteRemover;
@@ -307,18 +317,6 @@ private:
/** The top level substitutions */
SubstitutionMap d_topLevelSubstitutions;
- /**
- * The last substitution that the SAT layer was told about.
- * In incremental settings, substitutions cannot be performed
- * "backward," only forward. So SAT needs to be told of all
- * substitutions that are going to be done. This iterator
- * holds the last substitution from d_topLevelSubstitutions
- * that was pushed out to SAT.
- * If d_lastSubstitutionPos == d_topLevelSubstitutions.end(),
- * then nothing has been pushed out yet.
- */
- context::CDO<SubstitutionMap::iterator> d_lastSubstitutionPos;
-
static const bool d_doConstantProp = true;
/**
@@ -350,8 +348,8 @@ private:
bool checkForBadSkolems(TNode n, TNode skolem, hash_map<Node, bool, NodeHashFunction>& cache);
// Lift bit-vectors of size 1 to booleans
- void bvToBool();
-
+ void bvToBool();
+
// Simplify ITE structure
void simpITE();
@@ -394,6 +392,8 @@ public:
d_propagator(d_nonClausalLearnedLiterals, true, true),
d_propagatorNeedsFinish(false),
d_assertionsToCheck(),
+ d_assertionsProcessed(smt.d_userContext, false),
+ d_substitutionsIndex(smt.d_userContext, 0),
d_fakeContext(),
d_abstractValueMap(&d_fakeContext),
d_abstractValues(),
@@ -402,9 +402,10 @@ public:
d_modZero(),
d_iteSkolemMap(),
d_iteRemover(smt.d_userContext),
- d_topLevelSubstitutions(smt.d_userContext),
- d_lastSubstitutionPos(smt.d_userContext, d_topLevelSubstitutions.end()) {
+ d_topLevelSubstitutions(smt.d_userContext)
+ {
d_smt.d_nodeManager->subscribeEvents(this);
+ d_true = NodeManager::currentNM()->mkConst(true);
}
~SmtEnginePrivate() {
@@ -419,11 +420,13 @@ public:
d_smt.d_nodeManager->unsubscribeEvents(this);
}
- void nmNotifyNewSort(TypeNode tn) {
+ void nmNotifyNewSort(TypeNode tn, uint32_t flags) {
DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()),
0,
tn.toType());
- d_smt.addToModelCommandAndDump(c);
+ if((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0) {
+ d_smt.addToModelCommandAndDump(c, flags);
+ }
}
void nmNotifyNewSortConstructor(TypeNode tn) {
@@ -438,17 +441,19 @@ public:
d_smt.addToModelCommandAndDump(c);
}
- void nmNotifyNewVar(TNode n, bool isGlobal) {
+ void nmNotifyNewVar(TNode n, uint32_t flags) {
DeclareFunctionCommand c(n.getAttribute(expr::VarNameAttr()),
n.toExpr(),
n.getType().toType());
- d_smt.addToModelCommandAndDump(c, isGlobal);
+ if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
+ d_smt.addToModelCommandAndDump(c, flags);
+ }
if(n.getType().isBoolean() && !options::incrementalSolving()) {
d_boolVars.push_back(n);
}
}
- void nmNotifyNewSkolem(TNode n, const std::string& comment, bool isGlobal) {
+ void nmNotifyNewSkolem(TNode n, const std::string& comment, uint32_t flags) {
string id = n.getAttribute(expr::VarNameAttr());
DeclareFunctionCommand c(id,
n.toExpr(),
@@ -456,7 +461,9 @@ public:
if(Dump.isOn("skolems") && comment != "") {
Dump("skolems") << CommentCommand(id + " is " + comment);
}
- d_smt.addToModelCommandAndDump(c, isGlobal, false, "skolems");
+ if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
+ d_smt.addToModelCommandAndDump(c, flags, false, "skolems");
+ }
if(n.getType().isBoolean() && !options::incrementalSolving()) {
d_boolVars.push_back(n);
}
@@ -678,7 +685,7 @@ void SmtEngine::finalOptionsAreSet() {
return;
}
- if (options::bitvectorEagerBitblast()) {
+ if(options::bitvectorEagerBitblast()) {
// Eager solver should use the internal decision strategy
options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
}
@@ -792,21 +799,24 @@ SmtEngine::~SmtEngine() throw() {
void SmtEngine::setLogic(const LogicInfo& logic) throw(ModalException) {
SmtScope smts(this);
-
+ if(d_fullyInited) {
+ throw ModalException("Cannot set logic in SmtEngine after the engine has finished initializing");
+ }
d_logic = logic;
setLogicInternal();
}
-void SmtEngine::setLogic(const std::string& s) throw(ModalException) {
+void SmtEngine::setLogic(const std::string& s) throw(ModalException, LogicException) {
SmtScope smts(this);
-
- setLogic(LogicInfo(s));
+ try {
+ setLogic(LogicInfo(s));
+ } catch(IllegalArgumentException& e) {
+ throw LogicException(e.what());
+ }
}
-void SmtEngine::setLogic(const char* logic) throw(ModalException){
- SmtScope smts(this);
-
- setLogic(LogicInfo(string(logic)));
+void SmtEngine::setLogic(const char* logic) throw(ModalException, LogicException) {
+ setLogic(string(logic));
}
LogicInfo SmtEngine::getLogicInfo() const {
@@ -823,24 +833,12 @@ void SmtEngine::setLogicInternal() throw() {
d_logic.lock();
- // may need to force uninterpreted functions to be on for non-linear
- if(((d_logic.isTheoryEnabled(THEORY_ARITH) && !d_logic.isLinear()) ||
- d_logic.isTheoryEnabled(THEORY_BV)) &&
- !d_logic.isTheoryEnabled(THEORY_UF)){
- d_logic = d_logic.getUnlockedCopy();
- d_logic.enableTheory(THEORY_UF);
- d_logic.lock();
- }
-
// Set the options for the theoryOf
if(!options::theoryOfMode.wasSetByUser()) {
if(d_logic.isSharingEnabled() && !d_logic.isTheoryEnabled(THEORY_BV)) {
- Theory::setTheoryOfMode(THEORY_OF_TERM_BASED);
- } else {
- Theory::setTheoryOfMode(THEORY_OF_TYPE_BASED);
+ Trace("smt") << "setting theoryof-mode to term-based" << endl;
+ options::theoryOfMode.set(THEORY_OF_TERM_BASED);
}
- } else {
- Theory::setTheoryOfMode(options::theoryOfMode());
}
// by default, symmetry breaker is on only for QF_UF
@@ -849,11 +847,10 @@ void SmtEngine::setLogicInternal() throw() {
Trace("smt") << "setting uf symmetry breaker to " << qf_uf << endl;
options::ufSymmetryBreaker.set(qf_uf);
}
- // by default, nonclausal simplification is off for QF_SAT and for quantifiers
+ // by default, nonclausal simplification is off for QF_SAT
if(! options::simplificationMode.wasSetByUser()) {
bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
- bool quantifiers = d_logic.isQuantified();
- Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << endl;
+ 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 ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
options::simplificationMode.set(qf_sat ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
@@ -990,14 +987,16 @@ void SmtEngine::setLogicInternal() throw() {
d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
) ||
// Quantifiers
- d_logic.isQuantified()
+ d_logic.isQuantified() ||
+ // Strings
+ d_logic.isTheoryEnabled(THEORY_STRINGS)
? decision::DECISION_STRATEGY_JUSTIFICATION
: decision::DECISION_STRATEGY_INTERNAL
);
bool stoponly =
// ALL_SUPPORTED
- d_logic.hasEverything() ? false :
+ d_logic.hasEverything() || d_logic.isTheoryEnabled(THEORY_STRINGS) ? false :
( // QF_AUFLIA
(not d_logic.isQuantified() &&
d_logic.isTheoryEnabled(THEORY_ARRAY) &&
@@ -1020,11 +1019,21 @@ void SmtEngine::setLogicInternal() throw() {
//for finite model finding
if( ! options::instWhenMode.wasSetByUser()){
+ //instantiate only on last call
if( options::fmfInstEngine() ){
Trace("smt") << "setting inst when mode to LAST_CALL" << endl;
options::instWhenMode.set( INST_WHEN_LAST_CALL );
}
}
+ if ( ! options::fmfInstGen.wasSetByUser()) {
+ //if full model checking is on, disable inst-gen techniques
+ if( options::fmfFullModelCheck() ){
+ options::fmfInstGen.set( false );
+ }
+ }
+ if( options::ufssSymBreak() ){
+ options::sortInference.set( true );
+ }
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
@@ -1108,13 +1117,15 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
}
// Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
- if(key == "name" ||
- key == "source" ||
+ if(key == "source" ||
key == "category" ||
key == "difficulty" ||
key == "notes") {
// ignore these
return;
+ } else if(key == "name") {
+ d_filename = value.getValue();
+ return;
} else if(key == "smt-lib-version") {
if( (value.isInteger() && value.getIntegerValue() == Integer(2)) ||
(value.isRational() && value.getRationalValue() == Rational(2)) ||
@@ -1133,7 +1144,7 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
throw OptionException("argument to (set-info :status ..) must be "
"`sat' or `unsat' or `unknown'");
}
- d_status = Result(s);
+ d_status = Result(s, d_filename);
return;
}
throw UnrecognizedOptionException();
@@ -1166,7 +1177,7 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
return stats;
} else if(key == "error-behavior") {
// immediate-exit | continued-execution
- return SExpr::Keyword("immediate-exit");
+ return SExpr::Keyword("continued-execution");
} else if(key == "name") {
return Configuration::getName();
} else if(key == "version") {
@@ -1194,6 +1205,9 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
throw ModalException("Can't get-info :reason-unknown when the "
"last result wasn't unknown!");
}
+ } else if(key == "all-options") {
+ // get the options, like all-statistics
+ return Options::current().getOptions();
} else {
throw UnrecognizedOptionException();
}
@@ -1213,13 +1227,13 @@ void SmtEngine::defineFunction(Expr func,
throw TypeCheckingException(func, ss.str());
}
}
- if(Dump.isOn("declarations")) {
- stringstream ss;
- ss << Expr::setlanguage(Expr::setlanguage::getLanguage(Dump.getStream()))
- << func;
- DefineFunctionCommand c(ss.str(), func, formals, formula);
- addToModelCommandAndDump(c, false, true, "declarations");
- }
+
+ stringstream ss;
+ ss << Expr::setlanguage(Expr::setlanguage::getLanguage(Dump.getStream()))
+ << func;
+ DefineFunctionCommand c(ss.str(), func, formals, formula);
+ addToModelCommandAndDump(c, ExprManager::VAR_FLAG_NONE, true, "declarations");
+
SmtScope smts(this);
// Substitute out any abstract values in formula
@@ -1316,6 +1330,11 @@ Node SmtEnginePrivate::expandBVDivByZero(TNode n) {
Node divTotalNumDen = nm->mkNode(n.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
kind::BITVECTOR_UREM_TOTAL, num, den);
Node node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
return node;
}
@@ -1323,168 +1342,209 @@ Node SmtEnginePrivate::expandBVDivByZero(TNode n) {
Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashFunction>& cache)
throw(TypeCheckingException, LogicException) {
- Kind k = n.getKind();
+ stack< triple<Node, Node, bool> > worklist;
+ stack<Node> result;
+ worklist.push(make_triple(Node(n), Node(n), false));
+
+ do {
+ n = worklist.top().first;
+ Node node = worklist.top().second;
+ bool childrenPushed = worklist.top().third;
+ worklist.pop();
- if(k != kind::APPLY && n.getNumChildren() == 0) {
- SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
- if(i != d_smt.d_definedFunctions->end()) {
- // replacement must be closed
- if((*i).second.getFormals().size() > 0) {
- return d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula());
+ if(!childrenPushed) {
+ Kind k = n.getKind();
+
+ if(k != kind::APPLY && n.getNumChildren() == 0) {
+ SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
+ if(i != d_smt.d_definedFunctions->end()) {
+ // replacement must be closed
+ if((*i).second.getFormals().size() > 0) {
+ result.push(d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula()));
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push((*i).second.getFormula());
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push(n);
+ continue;
}
- // don't bother putting in the cache
- return (*i).second.getFormula();
- }
- // don't bother putting in the cache
- return n;
- }
- // maybe it's in the cache
- hash_map<Node, Node, NodeHashFunction>::iterator cacheHit = cache.find(n);
- if(cacheHit != cache.end()) {
- TNode ret = (*cacheHit).second;
- return ret.isNull() ? n : ret;
- }
+ // maybe it's in the cache
+ hash_map<Node, Node, NodeHashFunction>::iterator cacheHit = cache.find(n);
+ if(cacheHit != cache.end()) {
+ TNode ret = (*cacheHit).second;
+ result.push(ret.isNull() ? n : ret);
+ continue;
+ }
- // otherwise expand it
+ // otherwise expand it
- Node node = n;
- NodeManager* nm = d_smt.d_nodeManager;
- // FIXME: this theory specific code should be factored out of the SmtEngine, somehow
- switch(k) {
- case kind::BITVECTOR_SDIV:
- case kind::BITVECTOR_SREM:
- case kind::BITVECTOR_SMOD: {
- node = bv::TheoryBVRewriter::eliminateBVSDiv(node);
- break;
- }
-
- case kind::BITVECTOR_UDIV:
- case kind::BITVECTOR_UREM: {
- node = expandBVDivByZero(node);
- break;
- }
- case kind::DIVISION: {
- // partial function: division
- if(d_smt.d_logic.isLinear()) {
- node = n;
- break;
- }
- if(d_divByZero.isNull()) {
- d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
- "partial real division", NodeManager::SKOLEM_EXACT_NAME);
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
- Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- break;
- }
-
- case kind::INTS_DIVISION: {
- // partial function: integer div
- if(d_smt.d_logic.isLinear()) {
- node = n;
- break;
- }
- if(d_intDivByZero.isNull()) {
- d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
- Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
- break;
- }
-
- case kind::INTS_MODULUS: {
- // partial function: mod
- if(d_smt.d_logic.isLinear()) {
- node = n;
- break;
- }
- if(d_modZero.isNull()) {
- d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
- Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
- break;
- }
-
- case kind::APPLY: {
- // application of a user-defined symbol
- TNode func = n.getOperator();
- SmtEngine::DefinedFunctionMap::const_iterator i =
- d_smt.d_definedFunctions->find(func);
- DefinedFunction def = (*i).second;
- vector<Node> formals = def.getFormals();
-
- if(Debug.isOn("expand")) {
- Debug("expand") << "found: " << n << endl;
- Debug("expand") << " func: " << func << endl;
- string name = func.getAttribute(expr::VarNameAttr());
- Debug("expand") << " : \"" << name << "\"" << endl;
- }
- if(i == d_smt.d_definedFunctions->end()) {
- throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'");
- }
- if(Debug.isOn("expand")) {
- Debug("expand") << " defn: " << def.getFunction() << endl
- << " [";
- if(formals.size() > 0) {
- copy( formals.begin(), formals.end() - 1,
- ostream_iterator<Node>(Debug("expand"), ", ") );
- Debug("expand") << formals.back();
+ NodeManager* nm = d_smt.d_nodeManager;
+ // FIXME: this theory-specific code should be factored out of the
+ // SmtEngine, somehow
+ switch(k) {
+ case kind::BITVECTOR_SDIV:
+ case kind::BITVECTOR_SREM:
+ case kind::BITVECTOR_SMOD:
+ node = bv::TheoryBVRewriter::eliminateBVSDiv(node);
+ break;
+
+ case kind::BITVECTOR_UDIV:
+ case kind::BITVECTOR_UREM:
+ node = expandBVDivByZero(node);
+ break;
+
+ case kind::DIVISION: {
+ // partial function: division
+ if(d_divByZero.isNull()) {
+ d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
+ "partial real division", NodeManager::SKOLEM_EXACT_NAME);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
+ }
+ TNode num = n[0], den = n[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
+ Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ break;
}
- Debug("expand") << "]" << endl
- << " " << def.getFunction().getType() << endl
- << " " << def.getFormula() << endl;
- }
- TNode fm = def.getFormula();
- Node instance = fm.substitute(formals.begin(), formals.end(),
- n.begin(), n.end());
- Debug("expand") << "made : " << instance << endl;
+ case kind::INTS_DIVISION: {
+ // partial function: integer div
+ if(d_intDivByZero.isNull()) {
+ d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
+ "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
+ }
+ TNode num = n[0], den = n[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
+ Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
+ break;
+ }
- Node expanded = expandDefinitions(instance, cache);
- cache[n] = (n == expanded ? Node::null() : expanded);
- return expanded;
- }
+ case kind::INTS_MODULUS: {
+ // partial function: mod
+ if(d_modZero.isNull()) {
+ d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
+ "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
+ if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(THEORY_UF);
+ d_smt.d_logic.lock();
+ }
+ }
+ TNode num = n[0], den = n[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
+ Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
+ break;
+ }
- default:
- // unknown kind for expansion, just iterate over the children
- node = n;
- }
+ case kind::ABS: {
+ Node out = nm->mkNode(kind::ITE, nm->mkNode(kind::LT, node[0], nm->mkConst(Rational(0))), nm->mkNode(kind::UMINUS, node[0]), node[0]);
+ cache[n] = out;
+ result.push(out);
+ continue;
+ }
- // there should be children here, otherwise we short-circuited a return, above
- Assert(node.getNumChildren() > 0);
+ case kind::APPLY: {
+ // application of a user-defined symbol
+ TNode func = n.getOperator();
+ SmtEngine::DefinedFunctionMap::const_iterator i =
+ d_smt.d_definedFunctions->find(func);
+ DefinedFunction def = (*i).second;
+ vector<Node> formals = def.getFormals();
+
+ if(Debug.isOn("expand")) {
+ Debug("expand") << "found: " << n << endl;
+ Debug("expand") << " func: " << func << endl;
+ string name = func.getAttribute(expr::VarNameAttr());
+ Debug("expand") << " : \"" << name << "\"" << endl;
+ }
+ if(i == d_smt.d_definedFunctions->end()) {
+ throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'");
+ }
+ if(Debug.isOn("expand")) {
+ Debug("expand") << " defn: " << def.getFunction() << endl
+ << " [";
+ if(formals.size() > 0) {
+ copy( formals.begin(), formals.end() - 1,
+ ostream_iterator<Node>(Debug("expand"), ", ") );
+ Debug("expand") << formals.back();
+ }
+ Debug("expand") << "]" << endl
+ << " " << def.getFunction().getType() << endl
+ << " " << def.getFormula() << endl;
+ }
- // the partial functions can fall through, in which case we still
- // consider their children
- Debug("expand") << "cons : " << node << endl;
- NodeBuilder<> nb(node.getKind());
- if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
- Debug("expand") << "op : " << node.getOperator() << endl;
- nb << node.getOperator();
- }
- for(Node::iterator i = node.begin(),
- iend = node.end();
- i != iend;
- ++i) {
- Node expanded = expandDefinitions(*i, cache);
- Debug("expand") << "exchld: " << expanded << endl;
- nb << expanded;
- }
- node = nb;
- cache[n] = n == node ? Node::null() : node;
- return node;
+ TNode fm = def.getFormula();
+ Node instance = fm.substitute(formals.begin(), formals.end(),
+ n.begin(), n.end());
+ Debug("expand") << "made : " << instance << endl;
+
+ Node expanded = expandDefinitions(instance, cache);
+ cache[n] = (n == expanded ? Node::null() : expanded);
+ result.push(expanded);
+ continue;
+ }
+
+ default:
+ // unknown kind for expansion, just iterate over the children
+ node = n;
+ }
+
+ // there should be children here, otherwise we short-circuited a result-push/continue, above
+ Assert(node.getNumChildren() > 0);
+
+ // the partial functions can fall through, in which case we still
+ // consider their children
+ worklist.push(make_triple(Node(n), node, true));
+
+ for(size_t i = 0; i < node.getNumChildren(); ++i) {
+ worklist.push(make_triple(node[i], node[i], false));
+ }
+
+ } else {
+
+ Debug("expand") << "cons : " << node << endl;
+ //cout << "cons : " << node << endl;
+ NodeBuilder<> nb(node.getKind());
+ if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ Debug("expand") << "op : " << node.getOperator() << endl;
+ //cout << "op : " << node.getOperator() << endl;
+ nb << node.getOperator();
+ }
+ for(size_t i = 0; i < node.getNumChildren(); ++i) {
+ Assert(!result.empty());
+ Node expanded = result.top();
+ result.pop();
+ //cout << "exchld : " << expanded << endl;
+ Debug("expand") << "exchld : " << expanded << endl;
+ nb << expanded;
+ }
+ node = nb;
+ cache[n] = n == node ? Node::null() : node;
+ result.push(node);
+ }
+ } while(!worklist.empty());
+
+ AlwaysAssert(result.size() == 1);
+
+ return result.top();
}
@@ -1666,6 +1726,10 @@ bool SmtEnginePrivate::nonClausalSimplify() {
<< "asserting to propagator" << endl;
for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
Assert(Rewriter::rewrite(d_assertionsToPreprocess[i]) == d_assertionsToPreprocess[i]);
+ // Don't reprocess substitutions
+ if (d_substitutionsIndex > 0 && i == d_substitutionsIndex) {
+ continue;
+ }
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertionsToPreprocess[i] << endl;
d_propagator.assertTrue(d_assertionsToPreprocess[i]);
}
@@ -1684,12 +1748,15 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// No, conflict, go through the literals and solve them
SubstitutionMap constantPropagations(d_smt.d_context);
+ SubstitutionMap newSubstitutions(d_smt.d_context);
+ SubstitutionMap::iterator pos;
unsigned j = 0;
for(unsigned i = 0, i_end = d_nonClausalLearnedLiterals.size(); i < i_end; ++ i) {
// Simplify the literal we learned wrt previous substitutions
Node learnedLiteral = d_nonClausalLearnedLiterals[i];
Assert(Rewriter::rewrite(learnedLiteral) == learnedLiteral);
- Node learnedLiteralNew = d_topLevelSubstitutions.apply(learnedLiteral);
+ Assert(d_topLevelSubstitutions.apply(learnedLiteral) == learnedLiteral);
+ Node learnedLiteralNew = newSubstitutions.apply(learnedLiteral);
if (learnedLiteral != learnedLiteralNew) {
learnedLiteral = Rewriter::rewrite(learnedLiteralNew);
}
@@ -1717,18 +1784,21 @@ bool SmtEnginePrivate::nonClausalSimplify() {
return false;
}
}
- // Solve it with the corresponding theory
+
+ // Solve it with the corresponding theory, possibly adding new
+ // substitutions to newSubstitutions
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "solving " << learnedLiteral << endl;
+
Theory::PPAssertStatus solveStatus =
- d_smt.d_theoryEngine->solve(learnedLiteral, d_topLevelSubstitutions);
+ d_smt.d_theoryEngine->solve(learnedLiteral, newSubstitutions);
switch (solveStatus) {
case Theory::PP_ASSERT_STATUS_SOLVED: {
// The literal should rewrite to true
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "solved " << learnedLiteral << endl;
- Assert(Rewriter::rewrite(d_topLevelSubstitutions.apply(learnedLiteral)).isConst());
+ Assert(Rewriter::rewrite(newSubstitutions.apply(learnedLiteral)).isConst());
// vector<pair<Node, Node> > equations;
// constantPropagations.simplifyLHS(d_topLevelSubstitutions, equations, true);
// if (equations.empty()) {
@@ -1763,6 +1833,7 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Assert(!t.isConst());
Assert(constantPropagations.apply(t) == t);
Assert(d_topLevelSubstitutions.apply(t) == t);
+ Assert(newSubstitutions.apply(t) == t);
constantPropagations.addSubstitution(t, c);
// vector<pair<Node,Node> > equations;a
// constantPropagations.simplifyLHS(t, c, equations, true);
@@ -1788,10 +1859,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// 3. if l -> r is a constant propagation and l is a subterm of l' with l' -> r' another constant propagation, then l'[l/r] -> r' should be a
// constant propagation too
// 4. each lhs of constantPropagations is different from each rhs
- SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin();
- for (; pos != d_topLevelSubstitutions.end(); ++pos) {
+ for (pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos) {
Assert((*pos).first.isVar());
- // Assert(d_topLevelSubstitutions.apply((*pos).second) == (*pos).second);
+ Assert(d_topLevelSubstitutions.apply((*pos).first) == (*pos).first);
+ Assert(d_topLevelSubstitutions.apply((*pos).second) == (*pos).second);
+ Assert(newSubstitutions.apply(newSubstitutions.apply((*pos).second)) == newSubstitutions.apply((*pos).second));
}
for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Assert((*pos).second.isConst());
@@ -1815,27 +1887,16 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// Resize the learnt
d_nonClausalLearnedLiterals.resize(j);
- //must add substitutions to model
- TheoryModel* m = d_smt.d_theoryEngine->getModel();
- if(m != NULL) {
- for( SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin(); pos != d_topLevelSubstitutions.end(); ++pos) {
- Node n = (*pos).first;
- Node v = (*pos).second;
- Trace("model") << "Add substitution : " << n << " " << v << endl;
- m->addSubstitution( n, v );
- }
- }
-
hash_set<TNode, TNodeHashFunction> s;
- Trace("debugging") << "NonClausal simplify pre-preprocess\n";
+ Trace("debugging") << "NonClausal simplify pre-preprocess\n";
for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
Node assertion = d_assertionsToPreprocess[i];
- Node assertionNew = d_topLevelSubstitutions.apply(assertion);
+ Node assertionNew = newSubstitutions.apply(assertion);
Trace("debugging") << "assertion = " << assertion << endl;
- Trace("debugging") << "assertionNew = " << assertionNew << endl;
+ Trace("debugging") << "assertionNew = " << assertionNew << endl;
if (assertion != assertionNew) {
assertion = Rewriter::rewrite(assertionNew);
- Trace("debugging") << "rewrite(assertion) = " << assertion << endl;
+ Trace("debugging") << "rewrite(assertion) = " << assertion << endl;
}
Assert(Rewriter::rewrite(assertion) == assertion);
for (;;) {
@@ -1844,11 +1905,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
break;
}
++d_smt.d_stats->d_numConstantProps;
- Trace("debugging") << "assertionNew = " << assertionNew << endl;
+ Trace("debugging") << "assertionNew = " << assertionNew << endl;
assertion = Rewriter::rewrite(assertionNew);
- Trace("debugging") << "assertionNew = " << assertionNew << endl;
+ Trace("debugging") << "assertionNew = " << assertionNew << endl;
}
- Trace("debugging") << "\n";
+ Trace("debugging") << "\n";
s.insert(assertion);
d_assertionsToCheck.push_back(assertion);
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
@@ -1857,34 +1918,44 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
d_assertionsToPreprocess.clear();
- NodeBuilder<> learnedBuilder(kind::AND);
- Assert(d_realAssertionsEnd <= d_assertionsToCheck.size());
- learnedBuilder << d_assertionsToCheck[d_realAssertionsEnd - 1];
-
- if( options::incrementalSolving() ||
- options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL ) {
- // Keep substitutions
- SubstitutionMap::iterator pos = d_lastSubstitutionPos;
- if(pos == d_topLevelSubstitutions.end()) {
- pos = d_topLevelSubstitutions.begin();
- } else {
- ++pos;
- }
-
- while(pos != d_topLevelSubstitutions.end()) {
- // Push out this substitution
- TNode lhs = (*pos).first, rhs = (*pos).second;
+ // If in incremental mode, add substitutions to the list of assertions
+ if (d_substitutionsIndex > 0) {
+ NodeBuilder<> substitutionsBuilder(kind::AND);
+ substitutionsBuilder << d_assertionsToCheck[d_substitutionsIndex];
+ pos = newSubstitutions.begin();
+ for (; pos != newSubstitutions.end(); ++pos) {
+ // Add back this substitution as an assertion
+ TNode lhs = (*pos).first, rhs = newSubstitutions.apply((*pos).second);
Node n = NodeManager::currentNM()->mkNode(lhs.getType().isBoolean() ? kind::IFF : kind::EQUAL, lhs, rhs);
- learnedBuilder << n;
+ substitutionsBuilder << n;
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n << endl;
- d_lastSubstitutionPos = pos;
- ++pos;
+ }
+ if (substitutionsBuilder.getNumChildren() > 1) {
+ d_assertionsToCheck[d_substitutionsIndex] =
+ Rewriter::rewrite(Node(substitutionsBuilder));
+ }
+ }
+ else {
+ // If not in incremental mode, must add substitutions to model
+ TheoryModel* m = d_smt.d_theoryEngine->getModel();
+ if(m != NULL) {
+ for(pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos) {
+ Node n = (*pos).first;
+ Node v = newSubstitutions.apply((*pos).second);
+ Trace("model") << "Add substitution : " << n << " " << v << endl;
+ m->addSubstitution( n, v );
+ }
}
}
+ NodeBuilder<> learnedBuilder(kind::AND);
+ Assert(d_realAssertionsEnd <= d_assertionsToCheck.size());
+ learnedBuilder << d_assertionsToCheck[d_realAssertionsEnd - 1];
+
for (unsigned i = 0; i < d_nonClausalLearnedLiterals.size(); ++ i) {
Node learned = d_nonClausalLearnedLiterals[i];
- Node learnedNew = d_topLevelSubstitutions.apply(learned);
+ Assert(d_topLevelSubstitutions.apply(learned) == learned);
+ Node learnedNew = newSubstitutions.apply(learned);
if (learned != learnedNew) {
learned = Rewriter::rewrite(learnedNew);
}
@@ -1908,10 +1979,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
d_nonClausalLearnedLiterals.clear();
- SubstitutionMap::iterator pos = constantPropagations.begin();
- for (; pos != constantPropagations.end(); ++pos) {
+
+ for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Node cProp = (*pos).first.eqNode((*pos).second);
- Node cPropNew = d_topLevelSubstitutions.apply(cProp);
+ Assert(d_topLevelSubstitutions.apply(cProp) == cProp);
+ Node cPropNew = newSubstitutions.apply(cProp);
if (cProp != cPropNew) {
cProp = Rewriter::rewrite(cPropNew);
Assert(Rewriter::rewrite(cProp) == cProp);
@@ -1926,6 +1998,11 @@ bool SmtEnginePrivate::nonClausalSimplify() {
<< cProp << endl;
}
+ // Add new substitutions to topLevelSubstitutions
+ // Note that we don't have to keep rhs's in full solved form
+ // because SubstitutionMap::apply does a fixed-point iteration when substituting
+ d_topLevelSubstitutions.addSubstitutions(newSubstitutions);
+
if(learnedBuilder.getNumChildren() > 1) {
d_assertionsToCheck[d_realAssertionsEnd - 1] =
Rewriter::rewrite(Node(learnedBuilder));
@@ -1939,7 +2016,7 @@ bool SmtEnginePrivate::nonClausalSimplify() {
void SmtEnginePrivate::bvToBool() {
Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl;
std::vector<Node> new_assertions;
- d_smt.d_theoryEngine->ppBvToBool(d_assertionsToCheck, new_assertions);
+ d_smt.d_theoryEngine->ppBvToBool(d_assertionsToCheck, new_assertions);
for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
d_assertionsToCheck[i] = Rewriter::rewrite(new_assertions[i]);
}
@@ -1950,8 +2027,7 @@ void SmtEnginePrivate::simpITE() {
Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl;
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
-
+ for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
d_assertionsToCheck[i] = d_smt.d_theoryEngine->ppSimpITE(d_assertionsToCheck[i]);
}
}
@@ -2039,7 +2115,6 @@ void SmtEnginePrivate::traceBackToAssertions(const std::vector<Node>& nodes, std
size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsigned>& toRemove) {
Assert(n.getKind() == kind::AND);
- Node trueNode = NodeManager::currentNM()->mkConst(true);
size_t removals = 0;
for(Node::iterator j = n.begin(); j != n.end(); ++j) {
size_t subremovals = 0;
@@ -2070,7 +2145,7 @@ size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsi
}
}
if(b.getNumChildren() == 0) {
- n = trueNode;
+ n = d_true;
b.clear();
} else if(b.getNumChildren() == 1) {
n = b[0];
@@ -2383,11 +2458,10 @@ void SmtEnginePrivate::doMiplibTrick() {
}
if(!removeAssertions.empty()) {
Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl;
- Node trueNode = nm->mkConst(true);
for(size_t i = 0; i < d_realAssertionsEnd; ++i) {
if(removeAssertions.find(d_assertionsToCheck[i].getId()) != removeAssertions.end()) {
Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertionsToCheck[i] << endl;
- d_assertionsToCheck[i] = trueNode;
+ d_assertionsToCheck[i] = d_true;
++d_smt.d_stats->d_numMiplibAssertionsRemoved;
} else if(d_assertionsToCheck[i].getKind() == kind::AND) {
size_t removals = removeFromConjunction(d_assertionsToCheck[i], removeAssertions);
@@ -2453,6 +2527,7 @@ bool SmtEnginePrivate::simplifyAssertions()
d_assertionsToCheck.swap(d_assertionsToPreprocess);
}
+ dumpAssertions("post-nonclausal", d_assertionsToCheck);
Trace("smt") << "POST nonClausalSimplify" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2470,6 +2545,7 @@ bool SmtEnginePrivate::simplifyAssertions()
}
}
+ dumpAssertions("post-theorypp", d_assertionsToCheck);
Trace("smt") << "POST theoryPP" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2480,6 +2556,7 @@ bool SmtEnginePrivate::simplifyAssertions()
simpITE();
}
+ dumpAssertions("post-itesimp", d_assertionsToCheck);
Trace("smt") << "POST iteSimp" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2490,6 +2567,7 @@ bool SmtEnginePrivate::simplifyAssertions()
unconstrainedSimp();
}
+ dumpAssertions("post-unconstrained", d_assertionsToCheck);
Trace("smt") << "POST unconstrainedSimp" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2506,6 +2584,7 @@ bool SmtEnginePrivate::simplifyAssertions()
}
}
+ dumpAssertions("post-repeatsimp", d_assertionsToCheck);
Trace("smt") << "POST repeatSimp" << endl;
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
@@ -2534,11 +2613,26 @@ Result SmtEngine::check() {
Trace("smt") << "SmtEngine::check(): processing assertions" << endl;
d_private->processAssertions();
+ // Turn off stop only for QF_LRA
+ // TODO: Bring up in a meeting where to put this
+ if(options::decisionStopOnly() && !options::decisionMode.wasSetByUser() ){
+ if( // QF_LRA
+ (not d_logic.isQuantified() &&
+ d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areIntegersUsed()
+ )){
+ if(d_private->d_iteSkolemMap.empty()){
+ options::decisionStopOnly.set(false);
+ d_decisionEngine->clearStrategies();
+ Trace("smt") << "SmtEngine::check(): turning off stop only" << endl;
+ }
+ }
+ }
+
unsigned long millis = 0;
if(d_timeBudgetCumulative != 0) {
millis = getTimeRemaining();
if(millis == 0) {
- return Result(Result::VALIDITY_UNKNOWN, Result::TIMEOUT);
+ return Result(Result::VALIDITY_UNKNOWN, Result::TIMEOUT, d_filename);
}
}
if(d_timeBudgetPerCall != 0 && (millis == 0 || d_timeBudgetPerCall < millis)) {
@@ -2549,7 +2643,7 @@ Result SmtEngine::check() {
if(d_resourceBudgetCumulative != 0) {
resource = getResourceRemaining();
if(resource == 0) {
- return Result(Result::VALIDITY_UNKNOWN, Result::RESOURCEOUT);
+ return Result(Result::VALIDITY_UNKNOWN, Result::RESOURCEOUT, d_filename);
}
}
if(d_resourceBudgetPerCall != 0 && (resource == 0 || d_resourceBudgetPerCall < resource)) {
@@ -2570,13 +2664,13 @@ Result SmtEngine::check() {
Trace("limit") << "SmtEngine::check(): cumulative millis " << d_cumulativeTimeUsed
<< ", conflicts " << d_cumulativeResourceUsed << endl;
- return result;
+ return Result(result, d_filename);
}
Result SmtEngine::quickCheck() {
Assert(d_fullyInited);
Trace("smt") << "SMT quickCheck()" << endl;
- return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK);
+ return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
}
@@ -2655,14 +2749,26 @@ void SmtEnginePrivate::processAssertions() {
Assert(d_assertionsToCheck.size() == 0);
- // any assertions added beyond realAssertionsEnd must NOT affect the
- // equisatisfiability
- d_realAssertionsEnd = d_assertionsToPreprocess.size();
- if(d_realAssertionsEnd == 0) {
+ if (d_assertionsToPreprocess.size() == 0) {
// nothing to do
return;
}
+ if (d_assertionsProcessed &&
+ ( options::incrementalSolving() ||
+ options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL )) {
+ // Placeholder for storing substitutions
+ d_substitutionsIndex = d_assertionsToPreprocess.size();
+ d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ }
+
+ // Add dummy assertion in last position - to be used as a
+ // placeholder for any new assertions to get added
+ d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ // any assertions added beyond realAssertionsEnd must NOT affect the
+ // equisatisfiability
+ d_realAssertionsEnd = d_assertionsToPreprocess.size();
+
// Assertions are NOT guaranteed to be rewritten by this point
dumpAssertions("pre-definition-expansion", d_assertionsToPreprocess);
@@ -2671,7 +2777,7 @@ void SmtEnginePrivate::processAssertions() {
Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_definitionExpansionTime);
hash_map<Node, Node, NodeHashFunction> cache;
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
+ for(unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
d_assertionsToPreprocess[i] =
expandDefinitions(d_assertionsToPreprocess[i], cache);
}
@@ -2740,6 +2846,7 @@ void SmtEnginePrivate::processAssertions() {
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
dumpAssertions("pre-substitution", d_assertionsToPreprocess);
+
// Apply the substitutions we already have, and normalize
Chat() << "applying substitutions..." << endl;
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
@@ -2754,6 +2861,14 @@ void SmtEnginePrivate::processAssertions() {
// Assertions ARE guaranteed to be rewritten by this point
+ if( d_smt.d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
+ CVC4::theory::strings::StringsPreprocess sp;
+ sp.simplify( d_assertionsToPreprocess );
+ for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
+ d_assertionsToPreprocess[i] = Rewriter::rewrite( d_assertionsToPreprocess[i] );
+ }
+ }
+
dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess);
if( options::preSkolemQuant() ){
//apply pre-skolemization to existential quantifiers
@@ -2778,6 +2893,12 @@ void SmtEnginePrivate::processAssertions() {
}while( success );
}
+ Trace("fo-rsn-enable") << std::endl;
+ if( options::foPropQuant() ){
+ FirstOrderPropagation fop;
+ fop.simplify( d_assertionsToPreprocess );
+ }
+
if( options::sortInference() ){
//sort inference technique
d_smt.d_theoryEngine->getSortInference()->simplify( d_assertionsToPreprocess );
@@ -2798,7 +2919,7 @@ void SmtEnginePrivate::processAssertions() {
}
dumpAssertions("post-static-learning", d_assertionsToCheck);
- // Lift bit-vectors of size 1 to bool
+ // Lift bit-vectors of size 1 to bool
if(options::bvToBool()) {
Chat() << "...doing bvToBool..." << endl;
bvToBool();
@@ -2808,7 +2929,7 @@ void SmtEnginePrivate::processAssertions() {
Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
-
+
dumpAssertions("pre-ite-removal", d_assertionsToCheck);
{
Chat() << "removing term ITEs..." << endl;
@@ -2883,7 +3004,7 @@ void SmtEnginePrivate::processAssertions() {
Rewriter::rewrite(Node(builder));
}
// For some reason this is needed for some benchmarks, such as
- // http://church.cims.nyu.edu/benchmarks/smtlib2/QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
+ // http://cvc4.cs.nyu.edu/benchmarks/smtlib2/QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
// Figure it out later
removeITEs();
// Assert(iteRewriteAssertionsEnd == d_assertionsToCheck.size());
@@ -2938,6 +3059,8 @@ void SmtEnginePrivate::processAssertions() {
}
}
+ d_assertionsProcessed = true;
+
d_assertionsToCheck.clear();
d_iteSkolemMap.clear();
}
@@ -2945,6 +3068,11 @@ void SmtEnginePrivate::processAssertions() {
void SmtEnginePrivate::addFormula(TNode n)
throw(TypeCheckingException, LogicException) {
+ if (n == d_true) {
+ // nothing to do
+ return;
+ }
+
Trace("smt") << "SmtEnginePrivate::addFormula(" << n << ")" << endl;
// Add the normalized formula to the queue
@@ -3130,7 +3258,7 @@ Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, Log
return quickCheck().asValidityResult();
}
-Node SmtEngine::postprocess(TNode node, TypeNode expectedType) {
+Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
ModelPostprocessor mpost;
NodeVisitor<ModelPostprocessor> visitor;
Node value = visitor.run(mpost, node);
@@ -3185,7 +3313,7 @@ Expr SmtEngine::expandDefinitions(const Expr& ex) throw(TypeCheckingException, L
return n.toExpr();
}
-Expr SmtEngine::getValue(const Expr& ex) throw(ModalException, TypeCheckingException, LogicException) {
+Expr SmtEngine::getValue(const Expr& ex) const throw(ModalException, TypeCheckingException, LogicException) {
Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
@@ -3300,7 +3428,7 @@ CVC4::SExpr SmtEngine::getAssignment() throw(ModalException) {
}
if(d_assignments == NULL) {
- return SExpr();
+ return SExpr(vector<SExpr>());
}
vector<SExpr> sexprs;
@@ -3340,7 +3468,7 @@ CVC4::SExpr SmtEngine::getAssignment() throw(ModalException) {
return SExpr(sexprs);
}
-void SmtEngine::addToModelCommandAndDump(const Command& c, bool isGlobal, bool userVisible, const char* dumpTag) {
+void SmtEngine::addToModelCommandAndDump(const Command& c, uint32_t flags, bool userVisible, const char* dumpTag) {
Trace("smt") << "SMT addToModelCommandAndDump(" << c << ")" << endl;
SmtScope smts(this);
// If we aren't yet fully inited, the user might still turn on
@@ -3353,7 +3481,7 @@ void SmtEngine::addToModelCommandAndDump(const Command& c, bool isGlobal, bool u
// and expects to find their cardinalities in the model.
if(/* userVisible && */ (!d_fullyInited || options::produceModels())) {
doPendingPops();
- if(isGlobal) {
+ if(flags & ExprManager::VAR_FLAG_GLOBAL) {
d_modelGlobalCommands.push_back(c.clone());
} else {
d_modelCommands->push_back(c.clone());
@@ -3391,7 +3519,9 @@ Model* SmtEngine::getModel() throw(ModalException) {
"Cannot get model when produce-models options is off.";
throw ModalException(msg);
}
- return d_theoryEngine->getModel();
+ TheoryModel* m = d_theoryEngine->getModel();
+ m->d_inputName = d_filename;
+ return m;
}
void SmtEngine::checkModel(bool hardFailure) {
@@ -3412,13 +3542,8 @@ void SmtEngine::checkModel(bool hardFailure) {
// Check individual theory assertions
d_theoryEngine->checkTheoryAssertionsWithModel();
- if(Notice.isOn()) {
- // This operator<< routine is non-const (i.e., takes a non-const Model&).
- // This confuses the Notice() output routines, so extract the ostream
- // from it and output it "manually." Should be fixed by making Model
- // accessors const.
- Notice.getStream() << *m;
- }
+ // Output the model
+ Notice() << *m;
// We have a "fake context" for the substitution map (we don't need it
// to be context-dependent)
@@ -3506,6 +3631,12 @@ void SmtEngine::checkModel(bool hardFailure) {
Debug("boolean-terms") << "++ got " << n << endl;
Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
+ if(Theory::theoryOf(n) != THEORY_REWRITERULES) {
+ // In case it's a quantifier (or contains one), look up its value before
+ // simplifying, or the quantifier might be irreparably altered.
+ n = m->getValue(n);
+ }
+
// Simplify the result.
n = d_private->simplify(n);
Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
@@ -3527,6 +3658,7 @@ void SmtEngine::checkModel(bool hardFailure) {
// but don't show up in our substitution map above.
n = m->getValue(n);
Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n << endl;
+ AlwaysAssert(!hardFailure || n.isConst() || n.getKind() == kind::LAMBDA);
// The result should be == true.
if(n != NodeManager::currentNM()->mkConst(true)) {
@@ -3612,6 +3744,11 @@ void SmtEngine::push() throw(ModalException, LogicException) {
d_needPostsolve = false;
}
+ // The problem isn't really "extended" yet, but this disallows
+ // get-model after a push, simplifying our lives somewhat and
+ // staying symmtric with pop.
+ d_problemExtended = true;
+
d_userLevels.push_back(d_userContext->getLevel());
internalPush();
Trace("userpushpop") << "SmtEngine: pushed to level "
@@ -3638,6 +3775,14 @@ void SmtEngine::pop() throw(ModalException) {
d_needPostsolve = false;
}
+ // The problem isn't really "extended" yet, but this disallows
+ // get-model after a pop, simplifying our lives somewhat. It might
+ // not be strictly necessary to do so, since the pops occur lazily,
+ // but also it would be weird to have a legally-executed (get-model)
+ // that only returns a subset of the assignment (because the rest
+ // is no longer in scope!).
+ d_problemExtended = true;
+
AlwaysAssert(d_userContext->getLevel() > 0);
AlwaysAssert(d_userLevels.back() < d_userContext->getLevel());
while (d_userLevels.back() < d_userContext->getLevel()) {
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index a22e34c21..9655297b3 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -189,9 +189,9 @@ class CVC4_PUBLIC SmtEngine {
bool d_fullyInited;
/**
- * Whether or not we have added any assertions/declarations/definitions
- * since the last checkSat/query (and therefore we're not responsible
- * for an assignment).
+ * Whether or not we have added any assertions/declarations/definitions,
+ * or done push/pop, since the last checkSat/query, and therefore we're
+ * not responsible for models or proofs.
*/
bool d_problemExtended;
@@ -234,6 +234,16 @@ class CVC4_PUBLIC SmtEngine {
Result d_status;
/**
+ * The name of the input (if any).
+ */
+ std::string d_filename;
+
+ /**
+ * Verbosity of various commands.
+ */
+ std::map<std::string, Integer> d_commandVerbosity;
+
+ /**
* A private utility class to SmtEngine.
*/
smt::SmtEnginePrivate* d_private;
@@ -249,7 +259,7 @@ class CVC4_PUBLIC SmtEngine {
* like turning datatypes back into tuples, length-1-bitvectors back
* into booleans, etc.
*/
- Node postprocess(TNode n, TypeNode expectedType);
+ Node postprocess(TNode n, TypeNode expectedType) const;
/**
* This is something of an "init" procedure, but is idempotent; call
@@ -326,7 +336,7 @@ class CVC4_PUBLIC SmtEngine {
* Add to Model command. This is used for recording a command
* that should be reported during a get-model call.
*/
- void addToModelCommandAndDump(const Command& c, bool isGlobal = false, bool userVisible = true, const char* dumpTag = "declarations");
+ void addToModelCommandAndDump(const Command& c, uint32_t flags = 0, bool userVisible = true, const char* dumpTag = "declarations");
/**
* Get the model (only if immediately preceded by a SAT
@@ -350,12 +360,12 @@ public:
/**
* Set the logic of the script.
*/
- void setLogic(const std::string& logic) throw(ModalException);
+ void setLogic(const std::string& logic) throw(ModalException, LogicException);
/**
* Set the logic of the script.
*/
- void setLogic(const char* logic) throw(ModalException);
+ void setLogic(const char* logic) throw(ModalException, LogicException);
/**
* Set the logic of the script.
@@ -444,7 +454,7 @@ public:
* by a SAT or INVALID query). Only permitted if the SmtEngine is
* set to operate interactively and produce-models is on.
*/
- Expr getValue(const Expr& e) throw(ModalException, TypeCheckingException, LogicException);
+ Expr getValue(const Expr& e) const throw(ModalException, TypeCheckingException, LogicException);
/**
* Add a function to the set of expressions whose value is to be
@@ -497,9 +507,11 @@ public:
/**
* Set a resource limit for SmtEngine operations. This is like a time
* limit, but it's deterministic so that reproducible results can be
- * obtained. However, please note that it may not be deterministic
- * between different versions of CVC4, or even the same version on
- * different platforms.
+ * obtained. Currently, it's based on the number of conflicts.
+ * However, please note that the definition may change between different
+ * versions of CVC4 (as may the number of conflicts required, anyway),
+ * and it might even be different between instances of the same version
+ * of CVC4 on different platforms.
*
* A cumulative and non-cumulative (per-call) resource limit can be
* set at the same time. A call to setResourceLimit() with
diff --git a/src/smt/smt_options_template.cpp b/src/smt/smt_options_template.cpp
index 638cf2f83..4edd91a8d 100644
--- a/src/smt/smt_options_template.cpp
+++ b/src/smt/smt_options_template.cpp
@@ -44,11 +44,29 @@ void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
Dump("benchmark") << SetOptionCommand(key, value);
}
+ if(key == "command-verbosity") {
+ if(!value.isAtom()) {
+ const vector<SExpr>& cs = value.getChildren();
+ if(cs.size() == 2 &&
+ (cs[0].isKeyword() || cs[0].isString()) &&
+ cs[1].isInteger()) {
+ string c = cs[0].getValue();
+ const Integer& v = cs[1].getIntegerValue();
+ if(v < 0 || v > 2) {
+ throw OptionException("command-verbosity must be 0, 1, or 2");
+ }
+ d_commandVerbosity[c] = v;
+ return;
+ }
+ }
+ throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
+ }
+
string optionarg = value.getValue();
${smt_setoption_handlers}
-#line 52 "${template}"
+#line 70 "${template}"
throw UnrecognizedOptionException(key);
}
@@ -59,13 +77,56 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
NodeManagerScope nms(d_nodeManager);
Trace("smt") << "SMT getOption(" << key << ")" << endl;
+
+ if(key.length() >= 18 &&
+ key.compare(0, 18, "command-verbosity:") == 0) {
+ map<string, Integer>::const_iterator i = d_commandVerbosity.find(key.c_str() + 18);
+ if(i != d_commandVerbosity.end()) {
+ return (*i).second;
+ }
+ i = d_commandVerbosity.find("*");
+ if(i != d_commandVerbosity.end()) {
+ return (*i).second;
+ }
+ return Integer(2);
+ }
+
if(Dump.isOn("benchmark")) {
Dump("benchmark") << GetOptionCommand(key);
}
+ if(key == "command-verbosity") {
+ vector<SExpr> result;
+ SExpr defaultVerbosity;
+ for(map<string, Integer>::const_iterator i = d_commandVerbosity.begin();
+ i != d_commandVerbosity.end();
+ ++i) {
+ vector<SExpr> v;
+ v.push_back((*i).first);
+ v.push_back((*i).second);
+ if((*i).first == "*") {
+ // put the default at the end of the SExpr
+ defaultVerbosity = v;
+ } else {
+ result.push_back(v);
+ }
+ }
+ // put the default at the end of the SExpr
+ if(!defaultVerbosity.isAtom()) {
+ result.push_back(defaultVerbosity);
+ } else {
+ // ensure the default is always listed
+ vector<SExpr> v;
+ v.push_back("*");
+ v.push_back(Integer(2));
+ result.push_back(v);
+ }
+ return result;
+ }
+
${smt_getoption_handlers}
-#line 69 "${template}"
+#line 130 "${template}"
throw UnrecognizedOptionException(key);
}
diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am
index bd7b881e1..860075aa8 100644
--- a/src/theory/Makefile.am
+++ b/src/theory/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = \
-I@builddir@/.. -I@srcdir@/../include -I@srcdir@/..
AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
-SUBDIRS = builtin booleans uf arith bv arrays datatypes quantifiers rewriterules
+SUBDIRS = builtin booleans uf arith bv arrays datatypes quantifiers rewriterules idl strings
DIST_SUBDIRS = $(SUBDIRS) example
noinst_LTLIBRARIES = libtheory.la
@@ -42,7 +42,9 @@ libtheory_la_SOURCES = \
model.h \
model.cpp \
rep_set.h \
- rep_set.cpp
+ rep_set.cpp \
+ atom_requests.h \
+ atom_requests.cpp
nodist_libtheory_la_SOURCES = \
rewriter_tables.h \
@@ -58,7 +60,9 @@ libtheory_la_LIBADD = \
@builddir@/bv/libbv.la \
@builddir@/datatypes/libdatatypes.la \
@builddir@/quantifiers/libquantifiers.la \
- @builddir@/rewriterules/librewriterules.la
+ @builddir@/rewriterules/librewriterules.la \
+ @builddir@/idl/libidl.la \
+ @builddir@/strings/libstrings.la
EXTRA_DIST = \
logic_info.i \
diff --git a/src/theory/arith/Makefile.am b/src/theory/arith/Makefile.am
index 3c664d806..620b8a121 100644
--- a/src/theory/arith/Makefile.am
+++ b/src/theory/arith/Makefile.am
@@ -51,8 +51,8 @@ libarith_la_SOURCES = \
soi_simplex.cpp \
approx_simplex.h \
approx_simplex.cpp \
- pure_update_simplex.h \
- pure_update_simplex.cpp \
+ attempt_solution_simplex.h \
+ attempt_solution_simplex.cpp \
theory_arith.h \
theory_arith.cpp \
theory_arith_private_forward.h \
diff --git a/src/theory/arith/approx_simplex.cpp b/src/theory/arith/approx_simplex.cpp
index d6be9f657..0f5a0fd4e 100644
--- a/src/theory/arith/approx_simplex.cpp
+++ b/src/theory/arith/approx_simplex.cpp
@@ -2,6 +2,7 @@
#include "theory/arith/approx_simplex.h"
#include "theory/arith/normal_form.h"
+#include "theory/arith/constraint.h"
#include <math.h>
#include <cmath>
@@ -94,6 +95,10 @@ public:
return Solution();
}
+ virtual ArithRatPairVec heuristicOptCoeffs() const{
+ return ArithRatPairVec();
+ }
+
virtual ApproxResult solveMIP(){
return ApproxError;
}
@@ -111,8 +116,14 @@ public:
/* Begin the declaration of GLPK specific code. */
#ifdef CVC4_USE_GLPK
extern "C" {
-#include <glpk.h>
-}
+/* Sometimes the header is in a subdirectory glpk/, sometimes not.
+ * The configure script figures it out. */
+#ifdef HAVE_GLPK_GLPK_H
+# include <glpk/glpk.h>
+#else /* HAVE_GLPK_GLPK_H */
+# include <glpk.h>
+#endif /* HAVE_GLPK_GLPK_H */
+}/* extern "C" */
namespace CVC4 {
namespace theory {
@@ -132,6 +143,8 @@ private:
bool d_solvedRelaxation;
bool d_solvedMIP;
+ static int s_verbosity;
+
public:
ApproxGLPK(const ArithVariables& vars);
~ApproxGLPK();
@@ -141,16 +154,22 @@ public:
return extractSolution(false);
}
+ virtual ArithRatPairVec heuristicOptCoeffs() const;
+
virtual ApproxResult solveMIP();
virtual Solution extractMIP() const{
return extractSolution(true);
}
virtual void setOptCoeffs(const ArithRatPairVec& ref);
+ static void printGLPKStatus(int status, std::ostream& out);
private:
Solution extractSolution(bool mip) const;
+ int guessDir(ArithVar v) const;
};
+int ApproxGLPK::s_verbosity = 0;
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
@@ -220,8 +239,10 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
ArithVar v = *vi;
- //cout << v << " ";
- //d_vars.printModel(v, cout);
+ if(s_verbosity >= 2){
+ Message() << v << " ";
+ d_vars.printModel(v, Message());
+ }
int type;
double lb = 0.0;
@@ -301,6 +322,189 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
delete[] ja;
delete[] ar;
}
+int ApproxGLPK::guessDir(ArithVar v) const{
+ if(d_vars.hasUpperBound(v) && !d_vars.hasLowerBound(v)){
+ return -1;
+ }else if(!d_vars.hasUpperBound(v) && d_vars.hasLowerBound(v)){
+ return 1;
+ }else if(!d_vars.hasUpperBound(v) && !d_vars.hasLowerBound(v)){
+ return 0;
+ }else{
+ int ubSgn = d_vars.getUpperBound(v).sgn();
+ int lbSgn = d_vars.getLowerBound(v).sgn();
+
+ if(ubSgn != 0 && lbSgn == 0){
+ return -1;
+ }else if(ubSgn == 0 && lbSgn != 0){
+ return 1;
+ }
+
+ return 1;
+ }
+}
+
+ArithRatPairVec ApproxGLPK::heuristicOptCoeffs() const{
+ ArithRatPairVec ret;
+
+ // Strategies are guess:
+ // 1 simple shared "ceiling" variable: danoint, pk1
+ // x1 >= c, x1 >= tmp1, x1 >= tmp2, ...
+ // 1 large row: fixnet, vpm2, pp08a
+ // (+ .......... ) <= c
+ // Not yet supported:
+ // 1 complex shared "ceiling" variable: opt1217
+ // x1 >= c, x1 >= (+ ..... ), x1 >= (+ ..... )
+ // and all of the ... are the same sign
+
+
+ // Candidates:
+ // 1) Upper and lower bounds are not equal.
+ // 2) The variable is not integer
+ // 3a) For columns look for a ceiling variable
+ // 3B) For rows look for a large row with
+
+ DenseMap<BoundCounts> d_colCandidates;
+ DenseMap<uint32_t> d_rowCandidates;
+
+ double sumRowLength = 0.0;
+ uint32_t maxRowLength = 0;
+ for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
+ ArithVar v = *vi;
+
+ if(s_verbosity >= 2){
+ Message() << v << " ";
+ d_vars.printModel(v, Message());
+ }
+
+ int type;
+ if(d_vars.hasUpperBound(v) && d_vars.hasLowerBound(v)){
+ if(d_vars.boundsAreEqual(v)){
+ type = GLP_FX;
+ }else{
+ type = GLP_DB;
+ }
+ }else if(d_vars.hasUpperBound(v) && !d_vars.hasLowerBound(v)){
+ type = GLP_UP;
+ }else if(!d_vars.hasUpperBound(v) && d_vars.hasLowerBound(v)){
+ type = GLP_LO;
+ }else{
+ type = GLP_FR;
+ }
+
+ if(type != GLP_FX && type != GLP_FR){
+
+ if(d_vars.isSlack(v)){
+ Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(v));
+ uint32_t len = p.size();
+ d_rowCandidates.set(v, len);
+ sumRowLength += len;
+ maxRowLength =std::max(maxRowLength, len);
+ }else if(!d_vars.isInteger(v)){
+ d_colCandidates.set(v, BoundCounts());
+ }
+ }
+ }
+
+ uint32_t maxCount = 0;
+ for(DenseMap<int>::const_iterator i = d_rowIndices.begin(), i_end = d_rowIndices.end(); i != i_end; ++i){
+ ArithVar v = *i;
+
+ bool lbCap = d_vars.hasLowerBound(v) && !d_vars.hasUpperBound(v);
+ bool ubCap = !d_vars.hasLowerBound(v) && d_vars.hasUpperBound(v);
+
+ if(lbCap || ubCap){
+ Constraint b = lbCap ? d_vars.getLowerBoundConstraint(v)
+ : d_vars.getUpperBoundConstraint(v);
+
+ if(!(b->getValue()).noninfinitesimalIsZero()){ continue; }
+
+ Polynomial poly = Polynomial::parsePolynomial(d_vars.asNode(v));
+ if(poly.size() != 2) { continue; }
+
+ Polynomial::iterator j = poly.begin();
+ Monomial first = *j;
+ ++j;
+ Monomial second = *j;
+
+ bool firstIsPos = first.constantIsPositive();
+ bool secondIsPos = second.constantIsPositive();
+
+ if(firstIsPos == secondIsPos){ continue; }
+
+ Monomial pos = firstIsPos == lbCap ? first : second;
+ Monomial neg = firstIsPos != lbCap ? first : second;
+ // pos >= neg
+ VarList p = pos.getVarList();
+ VarList n = neg.getVarList();
+ if(d_vars.hasArithVar(p.getNode())){
+ ArithVar ap = d_vars.asArithVar(p.getNode());
+ if( d_colCandidates.isKey(ap)){
+ BoundCounts bc = d_colCandidates.get(ap);
+ bc = BoundCounts(bc.lowerBoundCount(), bc.upperBoundCount()+1);
+ maxCount = std::max(maxCount, bc.upperBoundCount());
+ d_colCandidates.set(ap, bc);
+ }
+ }
+ if(d_vars.hasArithVar(n.getNode())){
+ ArithVar an = d_vars.asArithVar(n.getNode());
+ if( d_colCandidates.isKey(an)){
+ BoundCounts bc = d_colCandidates.get(an);
+ bc = BoundCounts(bc.lowerBoundCount()+1, bc.upperBoundCount());
+ maxCount = std::max(maxCount, bc.lowerBoundCount());
+ d_colCandidates.set(an, bc);
+ }
+ }
+ }
+ }
+
+ // Attempt row
+ double avgRowLength = d_rowCandidates.size() >= 1 ?
+ ( sumRowLength / d_rowCandidates.size() ) : 0.0;
+
+ // There is a large row among the candidates
+ bool guessARowCandidate = maxRowLength >= (10.0 * avgRowLength);
+
+ double rowLengthReq = (maxRowLength * .9);
+
+ if(guessARowCandidate){
+ for(DenseMap<uint32_t>::const_iterator i = d_rowCandidates.begin(), iend =d_rowCandidates.end(); i != iend; ++i ){
+ ArithVar r = *i;
+ uint32_t len = d_rowCandidates[r];
+
+ int dir = guessDir(r);
+ if(len >= rowLengthReq){
+ if(s_verbosity >= 1){
+ Message() << "high row " << r << " " << len << " " << avgRowLength << " " << dir<< endl;
+ d_vars.printModel(r, Message());
+ }
+ ret.push_back(ArithRatPair(r, Rational(dir)));
+ }
+ }
+ }
+
+ // Attempt columns
+ bool guessAColCandidate = maxCount >= 4;
+ if(guessAColCandidate){
+ for(DenseMap<BoundCounts>::const_iterator i = d_colCandidates.begin(), iend = d_colCandidates.end(); i != iend; ++i ){
+ ArithVar c = *i;
+ BoundCounts bc = d_colCandidates[c];
+
+ int dir = guessDir(c);
+ double ubScore = double(bc.upperBoundCount()) / maxCount;
+ double lbScore = double(bc.lowerBoundCount()) / maxCount;
+ if(ubScore >= .9 || lbScore >= .9){
+ if(s_verbosity >= 1){
+ Message() << "high col " << c << " " << bc << " " << ubScore << " " << lbScore << " " << dir << endl;
+ d_vars.printModel(c, Message());
+ }
+ ret.push_back(ArithRatPair(c, Rational(c)));
+ }
+ }
+ }
+
+
+ return ret;
+}
void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
DenseMap<double> nbCoeffs;
@@ -346,6 +550,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
}
}
+
/*
* rough strategy:
* real relaxation
@@ -361,7 +566,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
* check with FCSimplex
*/
-static void printGLPKStatus(int status, std::ostream& out){
+void ApproxGLPK::printGLPKStatus(int status, std::ostream& out){
switch(status){
case GLP_OPT:
out << "GLP_OPT" << endl;
@@ -406,77 +611,90 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
int glpk_index = isSlack ? d_rowIndices[vi] : d_colIndices[vi];
int status = isSlack ? glp_get_row_stat(d_prob, glpk_index) : glp_get_col_stat(d_prob, glpk_index);
- //cout << "assignment " << vi << endl;
+ if(s_verbosity >= 2){
+ Message() << "assignment " << vi << endl;
+ }
+
+ bool useDefaultAssignment = false;
switch(status){
case GLP_BS:
- //cout << "basic" << endl;
+ //Message() << "basic" << endl;
newBasis.add(vi);
+ useDefaultAssignment = true;
break;
case GLP_NL:
case GLP_NS:
if(!mip){
- //cout << "non-basic lb" << endl;
+ if(s_verbosity >= 2){ Message() << "non-basic lb" << endl; }
newValues.set(vi, d_vars.getLowerBound(vi));
- break;
- }// intentionally fall through otherwise
+ }else{// intentionally fall through otherwise
+ useDefaultAssignment = true;
+ }
+ break;
case GLP_NU:
if(!mip){
- // cout << "non-basic ub" << endl;
+ if(s_verbosity >= 2){ Message() << "non-basic ub" << endl; }
newValues.set(vi, d_vars.getUpperBound(vi));
- break;
- }// intentionally fall through otherwise
+ }else {// intentionally fall through otherwise
+ useDefaultAssignment = true;
+ }
+ break;
default:
{
- // cout << "non-basic other" << endl;
+ useDefaultAssignment = true;
+ }
+ break;
+ }
+
+ if(useDefaultAssignment){
+ if(s_verbosity >= 2){ Message() << "non-basic other" << endl; }
+
+ double newAssign =
+ mip ?
+ (isSlack ? glp_mip_row_val(d_prob, glpk_index) : glp_mip_col_val(d_prob, glpk_index))
+ : (isSlack ? glp_get_row_prim(d_prob, glpk_index) : glp_get_col_prim(d_prob, glpk_index));
+ const DeltaRational& oldAssign = d_vars.getAssignment(vi);
- double newAssign =
- mip ?
- (isSlack ? glp_mip_row_val(d_prob, glpk_index) : glp_mip_col_val(d_prob, glpk_index))
- : (isSlack ? glp_get_row_prim(d_prob, glpk_index) : glp_get_col_prim(d_prob, glpk_index));
- const DeltaRational& oldAssign = d_vars.getAssignment(vi);
+ if(d_vars.hasLowerBound(vi) &&
+ roughlyEqual(newAssign, d_vars.getLowerBound(vi).approx(SMALL_FIXED_DELTA))){
+ //Message() << " to lb" << endl;
- if(d_vars.hasLowerBound(vi) &&
- roughlyEqual(newAssign, d_vars.getLowerBound(vi).approx(SMALL_FIXED_DELTA))){
- //cout << " to lb" << endl;
+ newValues.set(vi, d_vars.getLowerBound(vi));
+ }else if(d_vars.hasUpperBound(vi) &&
+ roughlyEqual(newAssign, d_vars.getUpperBound(vi).approx(SMALL_FIXED_DELTA))){
+ newValues.set(vi, d_vars.getUpperBound(vi));
+ // Message() << " to ub" << endl;
+ }else{
- newValues.set(vi, d_vars.getLowerBound(vi));
- }else if(d_vars.hasUpperBound(vi) &&
- roughlyEqual(newAssign, d_vars.getUpperBound(vi).approx(SMALL_FIXED_DELTA))){
- newValues.set(vi, d_vars.getUpperBound(vi));
- // cout << " to ub" << endl;
+ double rounded = round(newAssign);
+ if(roughlyEqual(newAssign, rounded)){
+ // Message() << "roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
+ newAssign = rounded;
}else{
+ // Message() << "not roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
+ }
- double rounded = round(newAssign);
- if(roughlyEqual(newAssign, rounded)){
- // cout << "roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
- newAssign = rounded;
- }else{
- // cout << "not roughly equal " << rounded << " " << newAssign << " " << oldAssign << endl;
- }
-
- DeltaRational proposal = estimateWithCFE(newAssign);
-
-
- if(roughlyEqual(newAssign, oldAssign.approx(SMALL_FIXED_DELTA))){
- // cout << " to prev value" << newAssign << " " << oldAssign << endl;
- proposal = d_vars.getAssignment(vi);
- }
-
-
- if(d_vars.strictlyLessThanLowerBound(vi, proposal)){
- //cout << " round to lb " << d_vars.getLowerBound(vi) << endl;
- proposal = d_vars.getLowerBound(vi);
- }else if(d_vars.strictlyGreaterThanUpperBound(vi, proposal)){
- //cout << " round to ub " << d_vars.getUpperBound(vi) << endl;
- proposal = d_vars.getUpperBound(vi);
- }else{
- //cout << " use proposal" << proposal << " " << oldAssign << endl;
- }
- newValues.set(vi, proposal);
+ DeltaRational proposal = estimateWithCFE(newAssign);
+
+
+ if(roughlyEqual(newAssign, oldAssign.approx(SMALL_FIXED_DELTA))){
+ // Message() << " to prev value" << newAssign << " " << oldAssign << endl;
+ proposal = d_vars.getAssignment(vi);
}
- break;
+
+
+ if(d_vars.strictlyLessThanLowerBound(vi, proposal)){
+ //Message() << " round to lb " << d_vars.getLowerBound(vi) << endl;
+ proposal = d_vars.getLowerBound(vi);
+ }else if(d_vars.strictlyGreaterThanUpperBound(vi, proposal)){
+ //Message() << " round to ub " << d_vars.getUpperBound(vi) << endl;
+ proposal = d_vars.getUpperBound(vi);
+ }else{
+ //Message() << " use proposal" << proposal << " " << oldAssign << endl;
+ }
+ newValues.set(vi, proposal);
}
}
}
@@ -492,8 +710,10 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveRelaxation(){
parm.meth = GLP_PRIMAL;
parm.pricing = GLP_PT_PSE;
parm.it_lim = d_pivotLimit;
- //parm.msg_lev = GLP_MSG_ALL;
parm.msg_lev = GLP_MSG_OFF;
+ if(s_verbosity >= 1){
+ parm.msg_lev = GLP_MSG_ALL;
+ }
int res = glp_simplex(d_prob, &parm);
switch(res){
@@ -550,8 +770,10 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveMIP(){
parm.cov_cuts = GLP_ON;
parm.cb_func = stopAtBingoOrPivotLimit;
parm.cb_info = &d_pivotLimit;
- //parm.msg_lev = GLP_MSG_ALL;
parm.msg_lev = GLP_MSG_OFF;
+ if(s_verbosity >= 1){
+ parm.msg_lev = GLP_MSG_ALL;
+ }
int res = glp_intopt(d_prob, &parm);
switch(res){
diff --git a/src/theory/arith/approx_simplex.h b/src/theory/arith/approx_simplex.h
index a2f3cde24..a34c8981d 100644
--- a/src/theory/arith/approx_simplex.h
+++ b/src/theory/arith/approx_simplex.h
@@ -24,7 +24,7 @@ public:
/**
* If glpk is enabled, return a subclass that can do something.
- * If glpk is disabled, return a sublass that does nothing.
+ * If glpk is disabled, return a subclass that does nothing.
*/
static ApproximateSimplex* mkApproximateSimplexSolver(const ArithVariables& vars);
ApproximateSimplex();
@@ -44,18 +44,15 @@ public:
/** Sets a maximization criteria for the approximate solver.*/
virtual void setOptCoeffs(const ArithRatPairVec& ref) = 0;
+ virtual ArithRatPairVec heuristicOptCoeffs() const = 0;
+
virtual ApproxResult solveRelaxation() = 0;
virtual Solution extractRelaxation() const = 0;
virtual ApproxResult solveMIP() = 0;
virtual Solution extractMIP() const = 0;
- static void applySolution(LinearEqualityModule& linEq, const Solution& sol){
- linEq.forceNewBasis(sol.newBasis);
- linEq.updateMany(sol.newValues);
- }
-
- /** UTILIES FOR DEALING WITH ESTIMATES */
+ /** UTILITIES FOR DEALING WITH ESTIMATES */
static const double SMALL_FIXED_DELTA;
static const double TOLERENCE;
diff --git a/src/theory/arith/arith_rewriter.cpp b/src/theory/arith/arith_rewriter.cpp
index aa5049ed4..247c09294 100644
--- a/src/theory/arith/arith_rewriter.cpp
+++ b/src/theory/arith/arith_rewriter.cpp
@@ -29,7 +29,8 @@ namespace theory {
namespace arith {
bool ArithRewriter::isAtom(TNode n) {
- return arith::isRelationOperator(n.getKind());
+ Kind k = n.getKind();
+ return arith::isRelationOperator(k) || k == kind::IS_INTEGER || k == kind::DIVISIBLE;
}
RewriteResponse ArithRewriter::rewriteConstant(TNode t){
@@ -98,11 +99,28 @@ RewriteResponse ArithRewriter::preRewriteTerm(TNode t){
return preRewritePlus(t);
case kind::MULT:
return preRewriteMult(t);
- //case kind::INTS_DIVISION:
- //case kind::INTS_MODULUS:
+ case kind::INTS_DIVISION:
+ case kind::INTS_MODULUS:
+ return RewriteResponse(REWRITE_DONE, t);
case kind::INTS_DIVISION_TOTAL:
case kind::INTS_MODULUS_TOTAL:
return rewriteIntsDivModTotal(t,true);
+ case kind::ABS:
+ if(t[0].isConst()) {
+ const Rational& rat = t[0].getConst<Rational>();
+ if(rat >= 0) {
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ } else {
+ return RewriteResponse(REWRITE_DONE,
+ NodeManager::currentNM()->mkConst(-rat));
+ }
+ }
+ return RewriteResponse(REWRITE_DONE, t);
+ case kind::IS_INTEGER:
+ case kind::TO_INTEGER:
+ return RewriteResponse(REWRITE_DONE, t);
+ case kind::TO_REAL:
+ return RewriteResponse(REWRITE_DONE, t[0]);
default:
Unhandled(k);
}
@@ -126,11 +144,44 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
return postRewritePlus(t);
case kind::MULT:
return postRewriteMult(t);
- //case kind::INTS_DIVISION:
- //case kind::INTS_MODULUS:
+ case kind::INTS_DIVISION:
+ case kind::INTS_MODULUS:
+ return RewriteResponse(REWRITE_DONE, t);
case kind::INTS_DIVISION_TOTAL:
case kind::INTS_MODULUS_TOTAL:
return rewriteIntsDivModTotal(t, false);
+ case kind::ABS:
+ if(t[0].isConst()) {
+ const Rational& rat = t[0].getConst<Rational>();
+ if(rat >= 0) {
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ } else {
+ return RewriteResponse(REWRITE_DONE,
+ NodeManager::currentNM()->mkConst(-rat));
+ }
+ }
+ case kind::TO_REAL:
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ case kind::TO_INTEGER:
+ if(t[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(Rational(t[0].getConst<Rational>().floor())));
+ }
+ if(t[0].getType().isInteger()) {
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ }
+ //Unimplemented("TO_INTEGER, nonconstant");
+ //return rewriteToInteger(t);
+ return RewriteResponse(REWRITE_DONE, t);
+ case kind::IS_INTEGER:
+ if(t[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(t[0].getConst<Rational>().getDenominator() == 1));
+ }
+ if(t[0].getType().isInteger()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ //Unimplemented("IS_INTEGER, nonconstant");
+ //return rewriteIsInteger(t);
+ return RewriteResponse(REWRITE_DONE, t);
default:
Unreachable();
}
@@ -190,6 +241,25 @@ RewriteResponse ArithRewriter::postRewriteMult(TNode t){
}
RewriteResponse ArithRewriter::postRewriteAtom(TNode atom){
+ if(atom.getKind() == kind::IS_INTEGER) {
+ if(atom[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(atom[0].getConst<Rational>().isIntegral()));
+ }
+ if(atom[0].getType().isInteger()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ // not supported, but this isn't the right place to complain
+ return RewriteResponse(REWRITE_DONE, atom);
+ } else if(atom.getKind() == kind::DIVISIBLE) {
+ if(atom[0].isConst()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(bool((atom[0].getConst<Rational>() / atom.getOperator().getConst<Divisible>().k).isIntegral())));
+ }
+ if(atom.getOperator().getConst<Divisible>().k.isOne()) {
+ return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true));
+ }
+ return RewriteResponse(REWRITE_AGAIN, NodeManager::currentNM()->mkNode(kind::EQUAL, NodeManager::currentNM()->mkNode(kind::INTS_MODULUS_TOTAL, atom[0], NodeManager::currentNM()->mkConst(Rational(atom.getOperator().getConst<Divisible>().k))), NodeManager::currentNM()->mkConst(Rational(0))));
+ }
+
// left |><| right
TNode left = atom[0];
TNode right = atom[1];
@@ -217,6 +287,14 @@ RewriteResponse ArithRewriter::preRewriteAtom(TNode atom){
}else if(atom.getKind() == kind::LT){
Node geq = currNM->mkNode(kind::GEQ, atom[0], atom[1]);
return RewriteResponse(REWRITE_DONE, currNM->mkNode(kind::NOT, geq));
+ }else if(atom.getKind() == kind::IS_INTEGER){
+ if(atom[0].getType().isInteger()){
+ return RewriteResponse(REWRITE_DONE, currNM->mkConst(true));
+ }
+ }else if(atom.getKind() == kind::DIVISIBLE){
+ if(atom.getOperator().getConst<Divisible>().k.isOne()){
+ return RewriteResponse(REWRITE_DONE, currNM->mkConst(true));
+ }
}
return RewriteResponse(REWRITE_DONE, atom);
@@ -329,6 +407,13 @@ RewriteResponse ArithRewriter::rewriteIntsDivModTotal(TNode t, bool pre){
Assert(k == kind::INTS_DIVISION || k == kind::INTS_DIVISION_TOTAL);
return RewriteResponse(REWRITE_AGAIN, n);
}
+ }else if(dIsConstant && d.getConst<Rational>().isNegativeOne()){
+ if(k == kind::INTS_MODULUS || k == kind::INTS_MODULUS_TOTAL){
+ return RewriteResponse(REWRITE_DONE, mkRationalNode(0));
+ }else{
+ Assert(k == kind::INTS_DIVISION || k == kind::INTS_DIVISION_TOTAL);
+ return RewriteResponse(REWRITE_AGAIN, NodeManager::currentNM()->mkNode(kind::UMINUS, n));
+ }
}else if(dIsConstant && n.getKind() == kind::CONST_RATIONAL){
Assert(d.getConst<Rational>().isIntegral());
Assert(n.getConst<Rational>().isIntegral());
diff --git a/src/theory/arith/arith_static_learner.h b/src/theory/arith/arith_static_learner.h
index c4bf92a16..d8407eeba 100644
--- a/src/theory/arith/arith_static_learner.h
+++ b/src/theory/arith/arith_static_learner.h
@@ -23,7 +23,6 @@
#include "util/statistics_registry.h"
#include "theory/arith/arith_utilities.h"
-#include "theory/substitutions.h"
#include "context/context.h"
#include "context/cdlist.h"
diff --git a/src/theory/arith/attempt_solution_simplex.cpp b/src/theory/arith/attempt_solution_simplex.cpp
new file mode 100644
index 000000000..f0cecc24b
--- /dev/null
+++ b/src/theory/arith/attempt_solution_simplex.cpp
@@ -0,0 +1,135 @@
+
+#include "theory/arith/attempt_solution_simplex.h"
+#include "theory/arith/options.h"
+#include "theory/arith/constraint.h"
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+AttemptSolutionSDP::AttemptSolutionSDP(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc)
+ : SimplexDecisionProcedure(linEq, errors, conflictChannel, tvmalloc)
+ , d_statistics()
+{ }
+
+AttemptSolutionSDP::Statistics::Statistics():
+ d_searchTime("theory::arith::attempt::searchTime"),
+ d_queueTime("theory::arith::attempt::queueTime"),
+ d_conflicts("theory::arith::attempt::conflicts", 0)
+{
+ StatisticsRegistry::registerStat(&d_searchTime);
+ StatisticsRegistry::registerStat(&d_queueTime);
+ StatisticsRegistry::registerStat(&d_conflicts);
+}
+
+AttemptSolutionSDP::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_searchTime);
+ StatisticsRegistry::unregisterStat(&d_queueTime);
+ StatisticsRegistry::unregisterStat(&d_conflicts);
+}
+
+bool AttemptSolutionSDP::matchesNewValue(const DenseMap<DeltaRational>& nv, ArithVar v) const{
+ return nv[v] == d_variables.getAssignment(v);
+}
+
+Result::Sat AttemptSolutionSDP::attempt(const ApproximateSimplex::Solution& sol){
+ const DenseSet& newBasis = sol.newBasis;
+ const DenseMap<DeltaRational>& newValues = sol.newValues;
+
+ DenseSet needsToBeAdded;
+ for(DenseSet::const_iterator i = newBasis.begin(), i_end = newBasis.end(); i != i_end; ++i){
+ ArithVar b = *i;
+ if(!d_tableau.isBasic(b)){
+ needsToBeAdded.add(b);
+ }
+ }
+ DenseMap<DeltaRational>::const_iterator nvi = newValues.begin(), nvi_end = newValues.end();
+ for(; nvi != nvi_end; ++nvi){
+ ArithVar currentlyNb = *nvi;
+ if(!d_tableau.isBasic(currentlyNb)){
+ if(!matchesNewValue(newValues, currentlyNb)){
+ const DeltaRational& newValue = newValues[currentlyNb];
+ Trace("arith::updateMany")
+ << "updateMany:" << currentlyNb << " "
+ << d_variables.getAssignment(currentlyNb) << " to "<< newValue << endl;
+ d_linEq.update(currentlyNb, newValue);
+ Assert(d_variables.assignmentIsConsistent(currentlyNb));
+ }
+ }
+ }
+ d_errorSet.reduceToSignals();
+ d_errorSet.setSelectionRule(VAR_ORDER);
+
+ static int instance = 0;
+ ++instance;
+
+ if(processSignals()){
+ Debug("arith::findModel") << "attemptSolution("<< instance <<") early conflict" << endl;
+ d_conflictVariables.purge();
+ return Result::UNSAT;
+ }else if(d_errorSet.errorEmpty()){
+ Debug("arith::findModel") << "attemptSolution("<< instance <<") fixed itself" << endl;
+ return Result::SAT;
+ }
+
+ while(!needsToBeAdded.empty() && !d_errorSet.errorEmpty()){
+ ArithVar toRemove = ARITHVAR_SENTINEL;
+ ArithVar toAdd = ARITHVAR_SENTINEL;
+ DenseSet::const_iterator i = needsToBeAdded.begin(), i_end = needsToBeAdded.end();
+ for(; toAdd == ARITHVAR_SENTINEL && i != i_end; ++i){
+ ArithVar v = *i;
+
+ Tableau::ColIterator colIter = d_tableau.colIterator(v);
+ for(; !colIter.atEnd(); ++colIter){
+ const Tableau::Entry& entry = *colIter;
+ Assert(entry.getColVar() == v);
+ ArithVar b = d_tableau.rowIndexToBasic(entry.getRowIndex());
+ if(!newBasis.isMember(b)){
+ toAdd = v;
+
+ bool favorBOverToRemove =
+ (toRemove == ARITHVAR_SENTINEL) ||
+ (matchesNewValue(newValues, toRemove) && !matchesNewValue(newValues, b)) ||
+ (d_tableau.basicRowLength(toRemove) > d_tableau.basicRowLength(b));
+
+ if(favorBOverToRemove){
+ toRemove = b;
+ }
+ }
+ }
+ }
+ Assert(toRemove != ARITHVAR_SENTINEL);
+ Assert(toAdd != ARITHVAR_SENTINEL);
+
+ Trace("arith::forceNewBasis") << toRemove << " " << toAdd << endl;
+ //Message() << toRemove << " " << toAdd << endl;
+
+ d_linEq.pivotAndUpdate(toRemove, toAdd, newValues[toRemove]);
+
+ Trace("arith::forceNewBasis") << needsToBeAdded.size() << "to go" << endl;
+ //Message() << needsToBeAdded.size() << "to go" << endl;
+ needsToBeAdded.remove(toAdd);
+
+ bool conflict = processSignals();
+ if(conflict){
+ d_errorSet.reduceToSignals();
+ d_conflictVariables.purge();
+
+ return Result::UNSAT;
+ }
+ }
+ Assert( d_conflictVariables.empty() );
+
+ if(d_errorSet.errorEmpty()){
+ return Result::SAT;
+ }else{
+ d_errorSet.reduceToSignals();
+ return Result::SAT_UNKNOWN;
+ }
+}
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/pure_update_simplex.h b/src/theory/arith/attempt_solution_simplex.h
index 50b751d7b..5bcdc6aab 100644
--- a/src/theory/arith/pure_update_simplex.h
+++ b/src/theory/arith/attempt_solution_simplex.h
@@ -53,64 +53,43 @@
#pragma once
-#include "theory/arith/simplex.h"
-#include "util/dense_map.h"
#include "util/statistics_registry.h"
-#include <stdint.h>
-#include "theory/arith/arithvar.h"
-#include "theory/arith/delta_rational.h"
+#include "theory/arith/simplex.h"
+#include "theory/arith/approx_simplex.h"
namespace CVC4 {
namespace theory {
namespace arith {
-class PureUpdateSimplexDecisionProcedure : public SimplexDecisionProcedure{
+class AttemptSolutionSDP : public SimplexDecisionProcedure {
public:
- PureUpdateSimplexDecisionProcedure(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc);
+ AttemptSolutionSDP(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc);
- Result::Sat findModel(bool exactResult);
+ Result::Sat attempt(const ApproximateSimplex::Solution& sol);
-private:
- ArithVar d_focusErrorVar;
-
- bool attemptPureUpdates();
+ Result::Sat findModel(bool exactResult){
+ Unreachable();
+ }
- /**
- * This is the main simplex for DPLL(T) loop.
- * It runs for at most maxIterations.
- *
- * Returns true iff it has found a conflict.
- * d_conflictVariable will be set and the conflict for this row is reported.
- */
- bool searchForFeasibleSolution(uint32_t maxIterations);
+private:
+ bool matchesNewValue(const DenseMap<DeltaRational>& nv, ArithVar v) const;
bool processSignals(){
- TimerStat &timer = d_statistics.d_processSignalsTime;
- IntStat& conflictStat = d_statistics.d_foundConflicts;
+ TimerStat &timer = d_statistics.d_queueTime;
+ IntStat& conflictStat = d_statistics.d_conflicts;
return standardProcessSignals(timer, conflictStat);
}
-
/** These fields are designed to be accessible to TheoryArith methods. */
class Statistics {
public:
- IntStat d_pureUpdateFoundUnsat;
- IntStat d_pureUpdateFoundSat;
- IntStat d_pureUpdateMissed;
- IntStat d_pureUpdates;
- IntStat d_pureUpdateDropped;
- IntStat d_pureUpdateConflicts;
-
- IntStat d_foundConflicts;
-
- TimerStat d_attemptPureUpdatesTimer;
- TimerStat d_processSignalsTime;
-
- TimerStat d_constructionTimer;
+ TimerStat d_searchTime;
+ TimerStat d_queueTime;
+ IntStat d_conflicts;
Statistics();
~Statistics();
} d_statistics;
-};/* class PureUpdateSimplexDecisionProcedure */
+};/* class AttemptSolutionSDP */
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/arith/bound_counts.h b/src/theory/arith/bound_counts.h
index 954cc056a..49c1a94ce 100644
--- a/src/theory/arith/bound_counts.h
+++ b/src/theory/arith/bound_counts.h
@@ -1,3 +1,20 @@
+/********************* */
+/*! \file bound_counts.h
+ ** \verbatim
+ ** Original author: Tim King
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "cvc4_private.h"
#pragma once
@@ -10,62 +27,92 @@ namespace CVC4 {
namespace theory {
namespace arith {
-/**
- * x = \sum_{a < 0} a_i i + \sum_{b > 0} b_j j
- *
- * AtUpperBound = {assignment(i) = lb(i)} \cup {assignment(j) = ub(j)}
- * AtLowerBound = {assignment(i) = ub(i)} \cup {assignment(j) = lb(j)}
- */
class BoundCounts {
private:
- uint32_t d_atLowerBounds;
- uint32_t d_atUpperBounds;
+ uint32_t d_lowerBoundCount;
+ uint32_t d_upperBoundCount;
public:
- BoundCounts() : d_atLowerBounds(0), d_atUpperBounds(0) {}
+ BoundCounts() : d_lowerBoundCount(0), d_upperBoundCount(0) {}
BoundCounts(uint32_t lbs, uint32_t ubs)
- : d_atLowerBounds(lbs), d_atUpperBounds(ubs) {}
+ : d_lowerBoundCount(lbs), d_upperBoundCount(ubs) {}
bool operator==(BoundCounts bc) const {
- return d_atLowerBounds == bc.d_atLowerBounds
- && d_atUpperBounds == bc.d_atUpperBounds;
+ return d_lowerBoundCount == bc.d_lowerBoundCount
+ && d_upperBoundCount == bc.d_upperBoundCount;
}
bool operator!=(BoundCounts bc) const {
- return d_atLowerBounds != bc.d_atLowerBounds
- || d_atUpperBounds != bc.d_atUpperBounds;
+ return d_lowerBoundCount != bc.d_lowerBoundCount
+ || d_upperBoundCount != bc.d_upperBoundCount;
+ }
+ /** This is not a total order! */
+ bool operator>=(BoundCounts bc) const {
+ return d_lowerBoundCount >= bc.d_lowerBoundCount &&
+ d_upperBoundCount >= bc.d_upperBoundCount;
}
- inline bool isZero() const{ return d_atLowerBounds == 0 && d_atUpperBounds == 0; }
- inline uint32_t atLowerBounds() const{
- return d_atLowerBounds;
+
+ inline bool isZero() const{ return d_lowerBoundCount == 0 && d_upperBoundCount == 0; }
+ inline uint32_t lowerBoundCount() const{
+ return d_lowerBoundCount;
}
- inline uint32_t atUpperBounds() const{
- return d_atUpperBounds;
+ inline uint32_t upperBoundCount() const{
+ return d_upperBoundCount;
}
inline BoundCounts operator+(BoundCounts bc) const{
- return BoundCounts(d_atLowerBounds + bc.d_atLowerBounds,
- d_atUpperBounds + bc.d_atUpperBounds);
+ return BoundCounts(d_lowerBoundCount + bc.d_lowerBoundCount,
+ d_upperBoundCount + bc.d_upperBoundCount);
}
inline BoundCounts operator-(BoundCounts bc) const {
- Assert(d_atLowerBounds >= bc.d_atLowerBounds);
- Assert(d_atUpperBounds >= bc.d_atUpperBounds);
- return BoundCounts(d_atLowerBounds - bc.d_atLowerBounds,
- d_atUpperBounds - bc.d_atUpperBounds);
+ Assert( *this >= bc );
+ return BoundCounts(d_lowerBoundCount - bc.d_lowerBoundCount,
+ d_upperBoundCount - bc.d_upperBoundCount);
+ }
+
+
+ inline BoundCounts& operator+=(BoundCounts bc) {
+ d_upperBoundCount += bc.d_upperBoundCount;
+ d_lowerBoundCount += bc.d_lowerBoundCount;
+ return *this;
+ }
+
+ inline BoundCounts& operator-=(BoundCounts bc) {
+ Assert(d_lowerBoundCount >= bc.d_lowerBoundCount);
+ Assert(d_upperBoundCount >= bc.d_upperBoundCount);
+ d_upperBoundCount -= bc.d_upperBoundCount;
+ d_lowerBoundCount -= bc.d_lowerBoundCount;
+
+ return *this;
+ }
+
+ /** Based on the sign coefficient a variable is multiplied by,
+ * the effects the bound counts either has no effect (sgn == 0),
+ * the lower bounds and upper bounds flip (sgn < 0), or nothing (sgn >0).
+ */
+ inline BoundCounts multiplyBySgn(int sgn) const{
+ if(sgn > 0){
+ return *this;
+ }else if(sgn == 0){
+ return BoundCounts(0,0);
+ }else{
+ return BoundCounts(d_upperBoundCount, d_lowerBoundCount);
+ }
}
inline void addInChange(int sgn, BoundCounts before, BoundCounts after){
- Assert(before != after);
- if(sgn < 0){
- Assert(d_atUpperBounds >= before.d_atLowerBounds);
- Assert(d_atLowerBounds >= before.d_atUpperBounds);
- d_atUpperBounds += after.d_atLowerBounds - before.d_atLowerBounds;
- d_atLowerBounds += after.d_atUpperBounds - before.d_atUpperBounds;
+ if(before == after){
+ return;
+ }else if(sgn < 0){
+ Assert(d_upperBoundCount >= before.d_lowerBoundCount);
+ Assert(d_lowerBoundCount >= before.d_upperBoundCount);
+ d_upperBoundCount += after.d_lowerBoundCount - before.d_lowerBoundCount;
+ d_lowerBoundCount += after.d_upperBoundCount - before.d_upperBoundCount;
}else if(sgn > 0){
- Assert(d_atUpperBounds >= before.d_atUpperBounds);
- Assert(d_atLowerBounds >= before.d_atLowerBounds);
- d_atUpperBounds += after.d_atUpperBounds - before.d_atUpperBounds;
- d_atLowerBounds += after.d_atLowerBounds - before.d_atLowerBounds;
+ Assert(d_upperBoundCount >= before.d_upperBoundCount);
+ Assert(d_lowerBoundCount >= before.d_lowerBoundCount);
+ d_upperBoundCount += after.d_upperBoundCount - before.d_upperBoundCount;
+ d_lowerBoundCount += after.d_lowerBoundCount - before.d_lowerBoundCount;
}
}
@@ -74,69 +121,112 @@ public:
Assert(!bc.isZero());
if(before < 0){
- d_atUpperBounds -= bc.d_atLowerBounds;
- d_atLowerBounds -= bc.d_atUpperBounds;
+ d_upperBoundCount -= bc.d_lowerBoundCount;
+ d_lowerBoundCount -= bc.d_upperBoundCount;
}else if(before > 0){
- d_atUpperBounds -= bc.d_atUpperBounds;
- d_atLowerBounds -= bc.d_atLowerBounds;
+ d_upperBoundCount -= bc.d_upperBoundCount;
+ d_lowerBoundCount -= bc.d_lowerBoundCount;
}
if(after < 0){
- d_atUpperBounds += bc.d_atLowerBounds;
- d_atLowerBounds += bc.d_atUpperBounds;
+ d_upperBoundCount += bc.d_lowerBoundCount;
+ d_lowerBoundCount += bc.d_upperBoundCount;
}else if(after > 0){
- d_atUpperBounds += bc.d_atUpperBounds;
- d_atLowerBounds += bc.d_atLowerBounds;
+ d_upperBoundCount += bc.d_upperBoundCount;
+ d_lowerBoundCount += bc.d_lowerBoundCount;
}
}
+};
- inline BoundCounts& operator+=(BoundCounts bc) {
- d_atUpperBounds += bc.d_atUpperBounds;
- d_atLowerBounds += bc.d_atLowerBounds;
- return *this;
- }
+class BoundsInfo {
+private:
- inline BoundCounts& operator-=(BoundCounts bc) {
- Assert(d_atLowerBounds >= bc.d_atLowerBounds);
- Assert(d_atUpperBounds >= bc.d_atUpperBounds);
- d_atUpperBounds -= bc.d_atUpperBounds;
- d_atLowerBounds -= bc.d_atLowerBounds;
+ /**
+ * x = \sum_{a < 0} a_i i + \sum_{b > 0} b_j j
+ *
+ * AtUpperBound = {assignment(i) = lb(i)} \cup {assignment(j) = ub(j)}
+ * AtLowerBound = {assignment(i) = ub(i)} \cup {assignment(j) = lb(j)}
+ */
+ BoundCounts d_atBounds;
- return *this;
+ /** This is for counting how many upper and lower bounds a row has. */
+ BoundCounts d_hasBounds;
+
+public:
+ BoundsInfo() : d_atBounds(), d_hasBounds() {}
+ BoundsInfo(BoundCounts atBounds, BoundCounts hasBounds)
+ : d_atBounds(atBounds), d_hasBounds(hasBounds) {}
+
+ BoundCounts atBounds() const { return d_atBounds; }
+ BoundCounts hasBounds() const { return d_hasBounds; }
+
+ /** This corresponds to adding in another variable to the row. */
+ inline BoundsInfo operator+(const BoundsInfo& bc) const{
+ return BoundsInfo(d_atBounds + bc.d_atBounds,
+ d_hasBounds + bc.d_hasBounds);
+ }
+ /** This corresponds to removing a variable from the row. */
+ inline BoundsInfo operator-(const BoundsInfo& bc) const {
+ Assert(*this >= bc);
+ return BoundsInfo(d_atBounds - bc.d_atBounds,
+ d_hasBounds - bc.d_hasBounds);
}
- inline BoundCounts multiplyBySgn(int sgn) const{
- if(sgn > 0){
- return *this;
- }else if(sgn == 0){
- return BoundCounts(0,0);
- }else{
- return BoundCounts(d_atUpperBounds, d_atLowerBounds);
- }
+ inline BoundsInfo& operator+=(const BoundsInfo& bc) {
+ d_atBounds += bc.d_atBounds;
+ d_hasBounds += bc.d_hasBounds;
+ return (*this);
}
-};
-typedef DenseMap<BoundCounts> BoundCountingVector;
+ /** Based on the sign coefficient a variable is multiplied by,
+ * the effects the bound counts either has no effect (sgn == 0),
+ * the lower bounds and upper bounds flip (sgn < 0), or nothing (sgn >0).
+ */
+ inline BoundsInfo multiplyBySgn(int sgn) const{
+ return BoundsInfo(d_atBounds.multiplyBySgn(sgn), d_hasBounds.multiplyBySgn(sgn));
+ }
-class BoundCountingLookup {
-private:
- BoundCountingVector* d_bc;
-public:
- BoundCountingLookup(BoundCountingVector* bc) : d_bc(bc) {}
- BoundCounts boundCounts(ArithVar v) const {
- Assert(d_bc->isKey(v));
- return (*d_bc)[v];
+ bool operator==(const BoundsInfo& other) const{
+ return d_atBounds == other.d_atBounds && d_hasBounds == other.d_hasBounds;
+ }
+ bool operator!=(const BoundsInfo& other) const{
+ return !(*this == other);
+ }
+ /** This is not a total order! */
+ bool operator>=(const BoundsInfo& other) const{
+ return d_atBounds >= other.d_atBounds && d_hasBounds >= other.d_hasBounds;
+ }
+ void addInChange(int sgn, const BoundsInfo& before, const BoundsInfo& after){
+ addInAtBoundChange(sgn, before.d_atBounds, after.d_atBounds);
+ addInHasBoundChange(sgn, before.d_hasBounds, after.d_hasBounds);
+ }
+ void addInAtBoundChange(int sgn, BoundCounts before, BoundCounts after){
+ d_atBounds.addInChange(sgn, before, after);
+ }
+ void addInHasBoundChange(int sgn, BoundCounts before, BoundCounts after){
+ d_hasBounds.addInChange(sgn, before, after);
+ }
+
+ inline void addInSgn(const BoundsInfo& bc, int before, int after){
+ if(!bc.d_atBounds.isZero()){ d_atBounds.addInSgn(bc.d_atBounds, before, after);}
+ if(!bc.d_hasBounds.isZero()){ d_hasBounds.addInSgn(bc.d_hasBounds, before, after);}
}
};
+/** This is intended to map each row to its relevant bound information. */
+typedef DenseMap<BoundsInfo> BoundInfoMap;
+
inline std::ostream& operator<<(std::ostream& os, const BoundCounts& bc){
- os << "[bc " << bc.atLowerBounds() << ", "
- << bc.atUpperBounds() << "]";
+ os << "[bc " << bc.lowerBoundCount() << ", " << bc.upperBoundCount() << "]";
return os;
}
-class BoundCountsCallback {
+inline std::ostream& operator<<(std::ostream& os, const BoundsInfo& inf){
+ os << "[bi : @ " << inf.atBounds() << ", " << inf.hasBounds() << "]";
+ return os;
+}
+class BoundUpdateCallback {
public:
- virtual void operator()(ArithVar v, BoundCounts bc) = 0;
+ virtual void operator()(ArithVar v, const BoundsInfo& up) = 0;
};
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/callbacks.cpp b/src/theory/arith/callbacks.cpp
index 6b6170b20..1e827d316 100644
--- a/src/theory/arith/callbacks.cpp
+++ b/src/theory/arith/callbacks.cpp
@@ -32,6 +32,10 @@ void RaiseConflict::operator()(Node n){
d_ta.raiseConflict(n);
}
+const BoundsInfo& BoundCountingLookup::boundsInfo(ArithVar basic) const{
+ return d_ta.boundsInfo(basic);
+}
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/callbacks.h b/src/theory/arith/callbacks.h
index 0d754d159..718799e9f 100644
--- a/src/theory/arith/callbacks.h
+++ b/src/theory/arith/callbacks.h
@@ -3,10 +3,10 @@
#include "expr/node.h"
#include "util/rational.h"
-#include "context/cdlist.h"
#include "theory/arith/theory_arith_private_forward.h"
#include "theory/arith/arithvar.h"
+#include "theory/arith/bound_counts.h"
namespace CVC4 {
namespace theory {
@@ -87,6 +87,20 @@ public:
void operator()(Node n);
};
+class BoundCountingLookup {
+private:
+ TheoryArithPrivate& d_ta;
+public:
+ BoundCountingLookup(TheoryArithPrivate& ta) : d_ta(ta) {}
+ const BoundsInfo& boundsInfo(ArithVar basic) const;
+ BoundCounts atBounds(ArithVar basic) const{
+ return boundsInfo(basic).atBounds();
+ }
+ BoundCounts hasBounds(ArithVar basic) const {
+ return boundsInfo(basic).hasBounds();
+ }
+};
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp
index e26687bf1..78b9d3494 100644
--- a/src/theory/arith/constraint.cpp
+++ b/src/theory/arith/constraint.cpp
@@ -922,6 +922,28 @@ bool ConstraintValue::proofIsEmpty() const{
return result;
}
+Node ConstraintValue::makeImplication(const std::vector<Constraint>& b) const{
+ Node antecedent = makeConjunction(b);
+ Node implied = getLiteral();
+ return antecedent.impNode(implied);
+}
+
+
+Node ConstraintValue::makeConjunction(const std::vector<Constraint>& b){
+ NodeBuilder<> nb(kind::AND);
+ for(vector<Constraint>::const_iterator i = b.begin(), end = b.end(); i != end; ++i){
+ Constraint b_i = *i;
+ b_i->explainBefore(nb, AssertionOrderSentinel);
+ }
+ if(nb.getNumChildren() >= 2){
+ return nb;
+ }else if(nb.getNumChildren() == 1){
+ return nb[0];
+ }else{
+ return mkBoolNode(true);
+ }
+}
+
void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) const{
Assert(hasProof());
Assert(!isSelfExplaining() || assertedToTheTheory());
diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h
index a5d64a652..4966115d2 100644
--- a/src/theory/arith/constraint.h
+++ b/src/theory/arith/constraint.h
@@ -598,6 +598,8 @@ public:
void impliedBy(Constraint a, Constraint b);
void impliedBy(const std::vector<Constraint>& b);
+ Node makeImplication(const std::vector<Constraint>& b) const;
+ static Node makeConjunction(const std::vector<Constraint>& b);
/** The node must have a proof already and be eligible for propagation! */
void propagate();
diff --git a/src/theory/arith/dual_simplex.cpp b/src/theory/arith/dual_simplex.cpp
index 7caee6708..a9304ae76 100644
--- a/src/theory/arith/dual_simplex.cpp
+++ b/src/theory/arith/dual_simplex.cpp
@@ -196,19 +196,19 @@ bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingI
//DeltaRational beta_i = d_variables.getAssignment(x_i);
ArithVar x_j = ARITHVAR_SENTINEL;
- int32_t prevErrorSize = d_errorSet.errorSize();
+ int32_t prevErrorSize CVC4_UNUSED = d_errorSet.errorSize();
if(d_variables.cmpAssignmentLowerBound(x_i) < 0 ){
x_j = d_linEq.selectSlackUpperBound(x_i, pf);
if(x_j == ARITHVAR_SENTINEL ){
Unreachable();
- ++(d_statistics.d_statUpdateConflicts);
- reportConflict(x_i);
- ++(d_statistics.d_simplexConflicts);
+ // ++(d_statistics.d_statUpdateConflicts);
+ // reportConflict(x_i);
+ // ++(d_statistics.d_simplexConflicts);
// Node conflict = d_linEq.generateConflictBelowLowerBound(x_i); //unsat
// d_conflictVariable = x_i;
// reportConflict(conflict);
- return true;
+ // return true;
}else{
const DeltaRational& l_i = d_variables.getLowerBound(x_i);
d_linEq.pivotAndUpdate(x_i, x_j, l_i);
@@ -217,13 +217,13 @@ bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingI
x_j = d_linEq.selectSlackLowerBound(x_i, pf);
if(x_j == ARITHVAR_SENTINEL ){
Unreachable();
- ++(d_statistics.d_statUpdateConflicts);
- reportConflict(x_i);
- ++(d_statistics.d_simplexConflicts);
+ // ++(d_statistics.d_statUpdateConflicts);
+ // reportConflict(x_i);
+ // ++(d_statistics.d_simplexConflicts);
// Node conflict = d_linEq.generateConflictAboveUpperBound(x_i); //unsat
// d_conflictVariable = x_i;
// reportConflict(conflict);
- return true;
+ // return true;
}else{
const DeltaRational& u_i = d_variables.getUpperBound(x_i);
d_linEq.pivotAndUpdate(x_i, x_j, u_i);
@@ -232,16 +232,19 @@ bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingI
Assert(x_j != ARITHVAR_SENTINEL);
bool conflict = processSignals();
- int32_t currErrorSize = d_errorSet.errorSize();
+ int32_t currErrorSize CVC4_UNUSED = d_errorSet.errorSize();
d_pivots++;
- // cout << "#" << d_pivots
- // << " c" << conflict
- // << " d" << (prevErrorSize - currErrorSize)
- // << " f" << d_errorSet.inError(x_j)
- // << " h" << d_conflictVariables.isMember(x_j)
- // << " " << x_i << "->" << x_j
- // << endl;
+ if(Debug.isOn("arith::dual")){
+ Debug("arith::dual")
+ << "#" << d_pivots
+ << " c" << conflict
+ << " d" << (prevErrorSize - currErrorSize)
+ << " f" << d_errorSet.inError(x_j)
+ << " h" << d_conflictVariables.isMember(x_j)
+ << " " << x_i << "->" << x_j
+ << endl;
+ }
if(conflict){
return true;
diff --git a/src/theory/arith/error_set.cpp b/src/theory/arith/error_set.cpp
index ee72d1949..dea78acf7 100644
--- a/src/theory/arith/error_set.cpp
+++ b/src/theory/arith/error_set.cpp
@@ -1,11 +1,11 @@
/********************* */
-/*! \file arith_priority_queue.cpp
+/*! \file error_set.cpp
** \verbatim
- ** Original author: taking
- ** Major contributors: mdeters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** Original author: Tim King
+ ** Major contributors: none
+ ** Minor contributors (to current version): Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
diff --git a/src/theory/arith/error_set.h b/src/theory/arith/error_set.h
index 91d7e49ea..d1b692cb4 100644
--- a/src/theory/arith/error_set.h
+++ b/src/theory/arith/error_set.h
@@ -1,11 +1,11 @@
/********************* */
-/*! \file arith_priority_queue.h
+/*! \file error_set.h
** \verbatim
- ** Original author: taking
+ ** Original author: Tim King
** Major contributors: none
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** Minor contributors (to current version): Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
@@ -26,9 +26,9 @@
#include "theory/arith/partial_model.h"
#include "theory/arith/arith_heuristic_pivot_rule.h"
#include "theory/arith/tableau_sizes.h"
+#include "theory/arith/callbacks.h"
#include "util/statistics_registry.h"
-//#include <boost/heap/d_ary_heap.hpp>
#if CVC4_GCC_HAS_PB_DS_BUG
// Unfortunate bug in some older GCCs (e.g., v4.2):
@@ -377,8 +377,8 @@ public:
uint32_t sumMetric(ArithVar a) const{
Assert(inError(a));
- BoundCounts bcs = d_boundLookup.boundCounts(a);
- uint32_t count = getSgn(a) > 0 ? bcs.atUpperBounds() : bcs.atLowerBounds();
+ BoundCounts bcs = d_boundLookup.atBounds(a);
+ uint32_t count = getSgn(a) > 0 ? bcs.upperBoundCount() : bcs.lowerBoundCount();
uint32_t length = d_tableauSizes.getRowLength(a);
diff --git a/src/theory/arith/fc_simplex.cpp b/src/theory/arith/fc_simplex.cpp
index ac4625ba3..e99e62505 100644
--- a/src/theory/arith/fc_simplex.cpp
+++ b/src/theory/arith/fc_simplex.cpp
@@ -289,7 +289,7 @@ UpdateInfo FCSimplexDecisionProcedure::selectPrimalUpdate(ArithVar basic, Linear
Debug("arith::selectPrimalUpdate")
<< "selectPrimalUpdate " << instance << endl
<< basic << " " << d_tableau.basicRowLength(basic)
- << " " << d_linEq._countBounds(basic) << endl;
+ << " " << d_linEq.debugBasicAtBoundCount(basic) << endl;
static const int s_maxCandidatesAfterImprove = 3;
bool isFocus = basic == d_focusErrorVar;
@@ -358,18 +358,9 @@ UpdateInfo FCSimplexDecisionProcedure::selectPrimalUpdate(ArithVar basic, Linear
ArithVar curr = cand.d_nb;
const Rational& coeff = *cand.d_coeff;
-#warning "Who is using computeSafeUpdate?"
LinearEqualityModule::UpdatePreferenceFunction leavingPrefFunc = selectLeavingFunction(curr);
UpdateInfo currProposal = d_linEq.speculativeUpdate(curr, coeff, leavingPrefFunc);
- //int curr_movement = cand.d_sgn;
- // if(isFocus){
- // currProposal = d_linEq.speculativeUpdate(curr, coeff, upf);
- // }else{
- // currProposal = UpdateInfo(curr, curr_movement);
- // d_linEq.computeSafeUpdate(currProposal, bpf);
- // }
-
Debug("arith::selectPrimalUpdate")
<< "selected " << selected << endl
<< "currProp " << currProposal << endl
@@ -505,7 +496,7 @@ void FCSimplexDecisionProcedure::debugPrintSignal(ArithVar updated) const{
int dir = !d_variables.assignmentIsConsistent(updated) ?
d_errorSet.getSgn(updated) : 0;
Debug("updateAndSignal") << " dir " << dir;
- Debug("updateAndSignal") << " _countBounds " << d_linEq._countBounds(updated) << endl;
+ Debug("updateAndSignal") << " debugBasicAtBoundCount " << d_linEq.debugBasicAtBoundCount(updated) << endl;
}
bool debugUpdatedBasic(const UpdateInfo& selected, ArithVar updated){
@@ -530,7 +521,7 @@ void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, Wit
ArithVar leaving = selected.leaving();
ss << "leaving " << leaving
<< " " << d_tableau.basicRowLength(leaving)
- << " " << d_linEq._countBounds(leaving)
+ << " " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
if(degenerate(w) && selected.describesPivot()){
@@ -539,7 +530,7 @@ void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, Wit
<< "degenerate " << leaving
<< ", atBounds " << d_linEq.basicsAtBounds(selected)
<< ", len " << d_tableau.basicRowLength(leaving)
- << ", bc " << d_linEq._countBounds(leaving)
+ << ", bc " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
}
diff --git a/src/theory/arith/kinds b/src/theory/arith/kinds
index 07cfcc9e5..a8a4047ca 100644
--- a/src/theory/arith/kinds
+++ b/src/theory/arith/kinds
@@ -23,8 +23,16 @@ operator INTS_DIVISION 2 "ints division (user symbol)"
operator INTS_DIVISION_TOTAL 2 "ints division with interpreted division by 0 (internal symbol)"
operator INTS_MODULUS 2 "ints modulus (user symbol)"
operator INTS_MODULUS_TOTAL 2 "ints modulus with interpreted division by 0 (internal symbol)"
+operator ABS 1 "absolute value"
+parameterized DIVISIBLE DIVISIBLE_OP 1 "divisibility-by-k predicate"
operator POW 2 "arithmetic power"
+constant DIVISIBLE_OP \
+ ::CVC4::Divisible \
+ ::CVC4::DivisibleHashFunction \
+ "util/divisible.h" \
+ "operator for the divisibility-by-k predicate"
+
sort REAL_TYPE \
Cardinality::REALS \
well-founded \
@@ -72,6 +80,10 @@ operator LEQ 2 "less than or equal, x <= y"
operator GT 2 "greater than, x > y"
operator GEQ 2 "greater than or equal, x >= y"
+operator IS_INTEGER 1 "term is integer"
+operator TO_INTEGER 1 "cast term to integer"
+operator TO_REAL 1 "cast term to real"
+
typerule PLUS ::CVC4::theory::arith::ArithOperatorTypeRule
typerule MULT ::CVC4::theory::arith::ArithOperatorTypeRule
typerule MINUS ::CVC4::theory::arith::ArithOperatorTypeRule
@@ -86,11 +98,17 @@ typerule LEQ ::CVC4::theory::arith::ArithPredicateTypeRule
typerule GT ::CVC4::theory::arith::ArithPredicateTypeRule
typerule GEQ ::CVC4::theory::arith::ArithPredicateTypeRule
-typerule INTS_DIVISION ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule INTS_MODULUS ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule TO_REAL ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule TO_INTEGER ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule IS_INTEGER ::CVC4::theory::arith::ArithUnaryPredicateTypeRule
+
+typerule ABS ::CVC4::theory::arith::IntOperatorTypeRule
+typerule INTS_DIVISION ::CVC4::theory::arith::IntOperatorTypeRule
+typerule INTS_MODULUS ::CVC4::theory::arith::IntOperatorTypeRule
+typerule DIVISIBLE ::CVC4::theory::arith::IntUnaryPredicateTypeRule
typerule DIVISION_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule INTS_DIVISION_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule INTS_MODULUS_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule INTS_DIVISION_TOTAL ::CVC4::theory::arith::IntOperatorTypeRule
+typerule INTS_MODULUS_TOTAL ::CVC4::theory::arith::IntOperatorTypeRule
endtheory
diff --git a/src/theory/arith/linear_equality.cpp b/src/theory/arith/linear_equality.cpp
index 42d8b41f8..5817a3629 100644
--- a/src/theory/arith/linear_equality.cpp
+++ b/src/theory/arith/linear_equality.cpp
@@ -25,18 +25,10 @@ namespace theory {
namespace arith {
/* Explicitly instatiate these functions. */
-template void LinearEqualityModule::propagateNonbasics<true>(ArithVar basic, Constraint c);
-template void LinearEqualityModule::propagateNonbasics<false>(ArithVar basic, Constraint c);
template ArithVar LinearEqualityModule::selectSlack<true>(ArithVar x_i, VarPreferenceFunction pf) const;
template ArithVar LinearEqualityModule::selectSlack<false>(ArithVar x_i, VarPreferenceFunction pf) const;
-// template bool LinearEqualityModule::preferNonDegenerate<true>(const UpdateInfo& a, const UpdateInfo& b) const;
-// template bool LinearEqualityModule::preferNonDegenerate<false>(const UpdateInfo& a, const UpdateInfo& b) const;
-
-// template bool LinearEqualityModule::preferErrorsFixed<true>(const UpdateInfo& a, const UpdateInfo& b) const;
-// template bool LinearEqualityModule::preferErrorsFixed<false>(const UpdateInfo& a, const UpdateInfo& b) const;
-
template bool LinearEqualityModule::preferWitness<true>(const UpdateInfo& a, const UpdateInfo& b) const;
template bool LinearEqualityModule::preferWitness<false>(const UpdateInfo& a, const UpdateInfo& b) const;
@@ -57,14 +49,13 @@ void Border::output(std::ostream& out) const{
<< "}";
}
-LinearEqualityModule::LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundCountingVector& boundTracking, BasicVarModelUpdateCallBack f):
+LinearEqualityModule::LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundInfoMap& boundsTracking, BasicVarModelUpdateCallBack f):
d_variables(vars),
d_tableau(t),
d_basicVariableUpdates(f),
d_increasing(1),
d_decreasing(-1),
- d_relevantErrorBuffer(),
- d_boundTracking(boundTracking),
+ d_btracking(boundsTracking),
d_areTracking(false),
d_trackCallback(this)
{}
@@ -77,7 +68,8 @@ LinearEqualityModule::Statistics::Statistics():
d_weakeningAttempts("theory::arith::weakening::attempts",0),
d_weakeningSuccesses("theory::arith::weakening::success",0),
d_weakenings("theory::arith::weakening::total",0),
- d_weakenTime("theory::arith::weakening::time")
+ d_weakenTime("theory::arith::weakening::time"),
+ d_forceTime("theory::arith::forcing::time")
{
StatisticsRegistry::registerStat(&d_statPivots);
StatisticsRegistry::registerStat(&d_statUpdates);
@@ -89,6 +81,7 @@ LinearEqualityModule::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_weakeningSuccesses);
StatisticsRegistry::registerStat(&d_weakenings);
StatisticsRegistry::registerStat(&d_weakenTime);
+ StatisticsRegistry::registerStat(&d_forceTime);
}
LinearEqualityModule::Statistics::~Statistics(){
@@ -102,50 +95,56 @@ LinearEqualityModule::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_weakeningSuccesses);
StatisticsRegistry::unregisterStat(&d_weakenings);
StatisticsRegistry::unregisterStat(&d_weakenTime);
+ StatisticsRegistry::unregisterStat(&d_forceTime);
}
-void LinearEqualityModule::includeBoundCountChange(ArithVar nb, BoundCounts prev){
- if(d_tableau.isBasic(nb)){
- return;
- }
- Assert(!d_tableau.isBasic(nb));
+
+void LinearEqualityModule::includeBoundUpdate(ArithVar v, const BoundsInfo& prev){
Assert(!d_areTracking);
- BoundCounts curr = d_variables.boundCounts(nb);
+ BoundsInfo curr = d_variables.boundsInfo(v);
Assert(prev != curr);
- Tableau::ColIterator basicIter = d_tableau.colIterator(nb);
+ Tableau::ColIterator basicIter = d_tableau.colIterator(v);
for(; !basicIter.atEnd(); ++basicIter){
const Tableau::Entry& entry = *basicIter;
- Assert(entry.getColVar() == nb);
+ Assert(entry.getColVar() == v);
int a_ijSgn = entry.getCoefficient().sgn();
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
-
- BoundCounts& counts = d_boundTracking.get(basic);
- Debug("includeBoundCountChange") << basic << " " << counts << " to " ;
- counts -= prev.multiplyBySgn(a_ijSgn);
- counts += curr.multiplyBySgn(a_ijSgn);
- Debug("includeBoundCountChange") << counts << " " << a_ijSgn << std::endl;
+ RowIndex ridx = entry.getRowIndex();
+ BoundsInfo& counts = d_btracking.get(ridx);
+ Debug("includeBoundUpdate") << d_tableau.rowIndexToBasic(ridx) << " " << counts << " to " ;
+ counts.addInChange(a_ijSgn, prev, curr);
+ Debug("includeBoundUpdate") << counts << " " << a_ijSgn << std::endl;
}
- d_boundTracking.set(nb, curr);
}
void LinearEqualityModule::updateMany(const DenseMap<DeltaRational>& many){
for(DenseMap<DeltaRational>::const_iterator i = many.begin(), i_end = many.end(); i != i_end; ++i){
ArithVar nb = *i;
- Assert(!d_tableau.isBasic(nb));
- const DeltaRational& newValue = many[nb];
- if(newValue != d_variables.getAssignment(nb)){
- Trace("arith::updateMany")
- << "updateMany:" << nb << " "
- << d_variables.getAssignment(nb) << " to "<< newValue << endl;
- update(nb, newValue);
+ if(!d_tableau.isBasic(nb)){
+ Assert(!d_tableau.isBasic(nb));
+ const DeltaRational& newValue = many[nb];
+ if(newValue != d_variables.getAssignment(nb)){
+ Trace("arith::updateMany")
+ << "updateMany:" << nb << " "
+ << d_variables.getAssignment(nb) << " to "<< newValue << endl;
+ update(nb, newValue);
+ }
}
}
}
+
+
+void LinearEqualityModule::applySolution(const DenseSet& newBasis, const DenseMap<DeltaRational>& newValues){
+ forceNewBasis(newBasis);
+ updateMany(newValues);
+}
+
void LinearEqualityModule::forceNewBasis(const DenseSet& newBasis){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_forceTime);
+ cout << "force begin" << endl;
DenseSet needsToBeAdded;
for(DenseSet::const_iterator i = newBasis.begin(), i_end = newBasis.end(); i != i_end; ++i){
ArithVar b = *i;
@@ -179,10 +178,12 @@ void LinearEqualityModule::forceNewBasis(const DenseSet& newBasis){
Assert(toAdd != ARITHVAR_SENTINEL);
Trace("arith::forceNewBasis") << toRemove << " " << toAdd << endl;
+ Message() << toRemove << " " << toAdd << endl;
d_tableau.pivot(toRemove, toAdd, d_trackCallback);
d_basicVariableUpdates(toAdd);
Trace("arith::forceNewBasis") << needsToBeAdded.size() << "to go" << endl;
+ Message() << needsToBeAdded.size() << "to go" << endl;
needsToBeAdded.remove(toAdd);
}
}
@@ -231,9 +232,9 @@ void LinearEqualityModule::updateTracked(ArithVar x_i, const DeltaRational& v){
<< d_variables.getAssignment(x_i) << "|-> " << v << endl;
- BoundCounts before = d_variables.boundCounts(x_i);
+ BoundCounts before = d_variables.atBoundCounts(x_i);
d_variables.setAssignment(x_i, v);
- BoundCounts after = d_variables.boundCounts(x_i);
+ BoundCounts after = d_variables.atBoundCounts(x_i);
bool anyChange = before != after;
@@ -242,17 +243,24 @@ void LinearEqualityModule::updateTracked(ArithVar x_i, const DeltaRational& v){
const Tableau::Entry& entry = *colIter;
Assert(entry.getColVar() == x_i);
- ArithVar x_j = d_tableau.rowIndexToBasic(entry.getRowIndex());
+ RowIndex ridx = entry.getRowIndex();
+ ArithVar x_j = d_tableau.rowIndexToBasic(ridx);
const Rational& a_ji = entry.getCoefficient();
const DeltaRational& assignment = d_variables.getAssignment(x_j);
DeltaRational nAssignment = assignment+(diff * a_ji);
Debug("update") << x_j << " " << a_ji << assignment << " -> " << nAssignment << endl;
+ BoundCounts xjBefore = d_variables.atBoundCounts(x_j);
d_variables.setAssignment(x_j, nAssignment);
+ BoundCounts xjAfter = d_variables.atBoundCounts(x_j);
- if(anyChange && basicIsTracked(x_j)){
- BoundCounts& next_bc_k = d_boundTracking.get(x_j);
- next_bc_k.addInChange(a_ji.sgn(), before, after);
+ Assert(rowIndexIsTracked(ridx));
+ BoundsInfo& next_bc_k = d_btracking.get(ridx);
+ if(anyChange){
+ next_bc_k.addInAtBoundChange(a_ji.sgn(), before, after);
+ }
+ if(xjBefore != xjAfter){
+ next_bc_k.addInAtBoundChange(-1, xjBefore, xjAfter);
}
d_basicVariableUpdates(x_j);
@@ -332,7 +340,7 @@ void LinearEqualityModule::debugCheckTracking(){
ArithVar var = entry.getColVar();
const Rational& coeff = entry.getCoefficient();
DeltaRational beta = d_variables.getAssignment(var);
- Debug("arith::tracking") << var << " " << d_variables.boundCounts(var)
+ Debug("arith::tracking") << var << " " << d_variables.boundsInfo(var)
<< " " << beta << coeff;
if(d_variables.hasLowerBound(var)){
Debug("arith::tracking") << "(lb " << d_variables.getLowerBound(var) << ")";
@@ -345,11 +353,12 @@ void LinearEqualityModule::debugCheckTracking(){
Debug("arith::tracking") << "end row"<< endl;
if(basicIsTracked(basic)){
- BoundCounts computed = computeBoundCounts(basic);
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ BoundsInfo computed = computeRowBoundInfo(ridx, false);
Debug("arith::tracking")
<< "computed " << computed
- << " tracking " << d_boundTracking[basic] << endl;
- Assert(computed == d_boundTracking[basic]);
+ << " tracking " << d_btracking[ridx] << endl;
+ Assert(computed == d_btracking[ridx]);
}
}
@@ -426,19 +435,19 @@ bool LinearEqualityModule::debugEntireLinEqIsConsistent(const string& s){
return result;
}
-DeltaRational LinearEqualityModule::computeBound(ArithVar basic, bool upperBound){
+DeltaRational LinearEqualityModule::computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const {
DeltaRational sum(0,0);
- for(Tableau::RowIterator i = d_tableau.basicRowIterator(basic); !i.atEnd(); ++i){
+ for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
const Tableau::Entry& entry = (*i);
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == basic) continue;
+ ArithVar v = entry.getColVar();
+ if(v == skip){ continue; }
+
const Rational& coeff = entry.getCoefficient();
- int sgn = coeff.sgn();
- bool ub = upperBound ? (sgn > 0) : (sgn < 0);
+ bool vUb = (rowUb == (coeff.sgn() > 0));
- const DeltaRational& bound = ub ?
- d_variables.getUpperBound(nonbasic):
- d_variables.getLowerBound(nonbasic);
+ const DeltaRational& bound = vUb ?
+ d_variables.getUpperBound(v):
+ d_variables.getLowerBound(v);
DeltaRational diff = bound * coeff;
sum = sum + diff;
@@ -449,7 +458,7 @@ DeltaRational LinearEqualityModule::computeBound(ArithVar basic, bool upperBound
/**
* Computes the value of a basic variable using the current assignment.
*/
-DeltaRational LinearEqualityModule::computeRowValue(ArithVar x, bool useSafe){
+DeltaRational LinearEqualityModule::computeRowValue(ArithVar x, bool useSafe) const{
Assert(d_tableau.isBasic(x));
DeltaRational sum(0);
@@ -465,76 +474,71 @@ DeltaRational LinearEqualityModule::computeRowValue(ArithVar x, bool useSafe){
return sum;
}
-bool LinearEqualityModule::hasBounds(ArithVar basic, bool upperBound){
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(basic); !iter.atEnd(); ++iter){
+const Tableau::Entry* LinearEqualityModule::rowLacksBound(RowIndex ridx, bool rowUb, ArithVar skip){
+ Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
+ for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
ArithVar var = entry.getColVar();
- if(var == basic) continue;
+ if(var == skip) { continue; }
+
int sgn = entry.getCoefficient().sgn();
- if(upperBound){
- if( (sgn < 0 && !d_variables.hasLowerBound(var)) ||
- (sgn > 0 && !d_variables.hasUpperBound(var))){
- return false;
- }
- }else{
- if( (sgn < 0 && !d_variables.hasUpperBound(var)) ||
- (sgn > 0 && !d_variables.hasLowerBound(var))){
- return false;
- }
+ bool selectUb = (rowUb == (sgn > 0));
+ bool hasBound = selectUb ?
+ d_variables.hasUpperBound(var):
+ d_variables.hasLowerBound(var);
+ if(!hasBound){
+ return &entry;
}
}
- return true;
+ return NULL;
}
-template <bool upperBound>
-void LinearEqualityModule::propagateNonbasics(ArithVar basic, Constraint c){
- Assert(d_tableau.isBasic(basic));
- Assert(c->getVariable() == basic);
+void LinearEqualityModule::propagateBasicFromRow(Constraint c){
+ Assert(c != NullConstraint);
+ Assert(c->isUpperBound() || c->isLowerBound());
Assert(!c->assertedToTheTheory());
- Assert(!upperBound || c->isUpperBound()); // upperbound implies c is an upperbound
- Assert(upperBound || c->isLowerBound()); // !upperbound implies c is a lowerbound
- //Assert(c->canBePropagated());
Assert(!c->hasProof());
- Debug("arith::explainNonbasics") << "LinearEqualityModule::explainNonbasics("
- << basic <<") start" << endl;
+ bool upperBound = c->isUpperBound();
+ ArithVar basic = c->getVariable();
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
vector<Constraint> bounds;
+ propagateRow(bounds, ridx, upperBound, c);
+ c->impliedBy(bounds);
+}
+
+void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c){
+ Assert(!c->assertedToTheTheory());
+ Assert(c->canBePropagated());
+ Assert(!c->hasProof());
+
+ ArithVar v = c->getVariable();
+ Debug("arith::explainNonbasics") << "LinearEqualityModule::explainNonbasics("
+ << v <<") start" << endl;
- Tableau::RowIterator iter = d_tableau.basicRowIterator(basic);
+ Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
ArithVar nonbasic = entry.getColVar();
- if(nonbasic == basic) continue;
+ if(nonbasic == v){ continue; }
const Rational& a_ij = entry.getCoefficient();
int sgn = a_ij.sgn();
Assert(sgn != 0);
- Constraint bound = NullConstraint;
- if(upperBound){
- if(sgn < 0){
- bound = d_variables.getLowerBoundConstraint(nonbasic);
- }else{
- Assert(sgn > 0);
- bound = d_variables.getUpperBoundConstraint(nonbasic);
- }
- }else{
- if(sgn < 0){
- bound = d_variables.getUpperBoundConstraint(nonbasic);
- }else{
- Assert(sgn > 0);
- bound = d_variables.getLowerBoundConstraint(nonbasic);
- }
- }
+ bool selectUb = rowUp ? (sgn > 0) : (sgn < 0);
+ Constraint bound = selectUb
+ ? d_variables.getUpperBoundConstraint(nonbasic)
+ : d_variables.getLowerBoundConstraint(nonbasic);
+
Assert(bound != NullConstraint);
Debug("arith::explainNonbasics") << "explainNonbasics" << bound << " for " << c << endl;
- bounds.push_back(bound);
+ into.push_back(bound);
}
- c->impliedBy(bounds);
Debug("arith::explainNonbasics") << "LinearEqualityModule::explainNonbasics("
- << basic << ") done" << endl;
+ << v << ") done" << endl;
}
Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic) const {
@@ -745,60 +749,35 @@ void LinearEqualityModule::stopTrackingBoundCounts(){
}
-void LinearEqualityModule::trackVariable(ArithVar x_i){
- Assert(!basicIsTracked(x_i));
- BoundCounts counts(0,0);
-
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(x_i); !iter.atEnd(); ++iter){
- const Tableau::Entry& entry = *iter;
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == x_i) continue;
-
- const Rational& a_ij = entry.getCoefficient();
- counts += (d_variables.oldBoundCounts(nonbasic)).multiplyBySgn(a_ij.sgn());
- }
- d_boundTracking.set(x_i, counts);
+void LinearEqualityModule::trackRowIndex(RowIndex ridx){
+ Assert(!rowIndexIsTracked(ridx));
+ BoundsInfo bi = computeRowBoundInfo(ridx, true);
+ d_btracking.set(ridx, bi);
}
-BoundCounts LinearEqualityModule::computeBoundCounts(ArithVar x_i) const{
- BoundCounts counts(0,0);
+BoundsInfo LinearEqualityModule::computeRowBoundInfo(RowIndex ridx, bool inQueue) const{
+ BoundsInfo bi;
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(x_i); !iter.atEnd(); ++iter){
+ Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
+ for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == x_i) continue;
-
+ ArithVar v = entry.getColVar();
const Rational& a_ij = entry.getCoefficient();
- counts += (d_variables.boundCounts(nonbasic)).multiplyBySgn(a_ij.sgn());
+ bi += (d_variables.selectBoundsInfo(v, inQueue)).multiplyBySgn(a_ij.sgn());
}
-
- return counts;
+ return bi;
}
-// BoundCounts LinearEqualityModule::cachingCountBounds(ArithVar x_i) const{
-// if(d_boundTracking.isKey(x_i)){
-// return d_boundTracking[x_i];
-// }else{
-// return computeBoundCounts(x_i);
-// }
-// }
-BoundCounts LinearEqualityModule::_countBounds(ArithVar x_i) const {
- Assert(d_boundTracking.isKey(x_i));
- return d_boundTracking[x_i];
+BoundCounts LinearEqualityModule::debugBasicAtBoundCount(ArithVar x_i) const {
+ return d_btracking[d_tableau.basicToRowIndex(x_i)].atBounds();
}
-// BoundCounts LinearEqualityModule::countBounds(ArithVar x_i){
-// if(d_boundTracking.isKey(x_i)){
-// return d_boundTracking[x_i];
-// }else{
-// BoundCounts bc = computeBoundCounts(x_i);
-// if(d_areTracking){
-// d_boundTracking.set(x_i,bc);
-// }
-// return bc;
-// }
-// }
-
+/**
+ * If the pivot described in u were performed,
+ * then the row would qualify as being either at the minimum/maximum
+ * to the non-basics being at their bounds.
+ * The minimum/maximum is determined by the direction the non-basic is changing.
+ */
bool LinearEqualityModule::basicsAtBounds(const UpdateInfo& u) const {
Assert(u.describesPivot());
@@ -814,289 +793,78 @@ bool LinearEqualityModule::basicsAtBounds(const UpdateInfo& u) const {
int toLB = (c->getType() == LowerBound ||
c->getType() == Equality) ? 1 : 0;
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
- BoundCounts bcs = d_boundTracking[basic];
+ BoundCounts bcs = d_btracking[ridx].atBounds();
// x = c*n + \sum d*m
- // n = 1/c * x + -1/c * (\sum d*m)
- BoundCounts nonb = bcs - d_variables.boundCounts(nonbasic).multiplyBySgn(coeffSgn);
+ // 0 = -x + c*n + \sum d*m
+ // n = 1/c * x + -1/c * (\sum d*m)
+ BoundCounts nonb = bcs - d_variables.atBoundCounts(nonbasic).multiplyBySgn(coeffSgn);
+ nonb.addInChange(-1, d_variables.atBoundCounts(basic), BoundCounts(toLB, toUB));
nonb = nonb.multiplyBySgn(-coeffSgn);
- nonb += BoundCounts(toLB, toUB).multiplyBySgn(coeffSgn);
uint32_t length = d_tableau.basicRowLength(basic);
Debug("basicsAtBounds")
<< "bcs " << bcs
<< "nonb " << nonb
<< "length " << length << endl;
-
+ // nonb has nb excluded.
if(nbdir < 0){
- return bcs.atLowerBounds() + 1 == length;
+ return nonb.lowerBoundCount() + 1 == length;
}else{
Assert(nbdir > 0);
- return bcs.atUpperBounds() + 1 == length;
+ return nonb.upperBoundCount() + 1 == length;
}
}
bool LinearEqualityModule::nonbasicsAtLowerBounds(ArithVar basic) const {
Assert(basicIsTracked(basic));
- BoundCounts bcs = d_boundTracking[basic];
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+
+ BoundCounts bcs = d_btracking[ridx].atBounds();
uint32_t length = d_tableau.basicRowLength(basic);
- return bcs.atLowerBounds() + 1 == length;
+ // return true if excluding the basic is every element is at its "lowerbound"
+ // The psuedo code is:
+ // bcs -= basic.count(basic, basic's sgn)
+ // return bcs.lowerBoundCount() + 1 == length
+ // As basic's sign is always -1, we can pull out the pieces of the count:
+ // bcs.lowerBoundCount() - basic.atUpperBoundInd() + 1 == length
+ // basic.atUpperBoundInd() is either 0 or 1
+ uint32_t lbc = bcs.lowerBoundCount();
+ return (lbc == length) ||
+ (lbc + 1 == length && d_variables.cmpAssignmentUpperBound(basic) != 0);
}
bool LinearEqualityModule::nonbasicsAtUpperBounds(ArithVar basic) const {
Assert(basicIsTracked(basic));
- BoundCounts bcs = d_boundTracking[basic];
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ BoundCounts bcs = d_btracking[ridx].atBounds();
uint32_t length = d_tableau.basicRowLength(basic);
+ uint32_t ubc = bcs.upperBoundCount();
+ // See the comment for nonbasicsAtLowerBounds()
- return bcs.atUpperBounds() + 1 == length;
-}
-
-void LinearEqualityModule::trackingSwap(ArithVar basic, ArithVar nb, int nbSgn) {
- Assert(basicIsTracked(basic));
-
- // z = a*x + \sum b*y
- // x = (1/a) z + \sum (-1/a)*b*y
- // basicCount(z) = bc(a*x) + bc(\sum b y)
- // basicCount(x) = bc(z/a) + bc(\sum -b/a * y)
-
- // sgn(1/a) = sgn(a)
- // bc(a*x) = bc(x).multiply(sgn(a))
- // bc(z/a) = bc(z).multiply(sgn(a))
- // bc(\sum -b/a * y) = bc(\sum b y).multiplyBySgn(-sgn(a))
- // bc(\sum b y) = basicCount(z) - bc(a*x)
- // basicCount(x) =
- // = bc(z).multiply(sgn(a)) + (basicCount(z) - bc(a*x)).multiplyBySgn(-sgn(a))
-
- BoundCounts bc = d_boundTracking[basic];
- bc -= (d_variables.boundCounts(nb)).multiplyBySgn(nbSgn);
- bc = bc.multiplyBySgn(-nbSgn);
- bc += d_variables.boundCounts(basic).multiplyBySgn(nbSgn);
- d_boundTracking.set(nb, bc);
- d_boundTracking.remove(basic);
-}
-
-void LinearEqualityModule::trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn){
- Assert(oldSgn != currSgn);
- BoundCounts nb_bc = d_variables.boundCounts(nb);
-
- if(!nb_bc.isZero()){
- ArithVar basic = d_tableau.rowIndexToBasic(ridx);
- Assert(basicIsTracked(basic));
-
- BoundCounts& basic_bc = d_boundTracking.get(basic);
- basic_bc.addInSgn(nb_bc, oldSgn, currSgn);
- }
+ return (ubc == length) ||
+ (ubc + 1 == length && d_variables.cmpAssignmentLowerBound(basic) != 0);
}
-void LinearEqualityModule::computeSafeUpdate(UpdateInfo& inf, VarPreferenceFunction pref){
- ArithVar nb = inf.nonbasic();
- int sgn = inf.nonbasicDirection();
+void LinearEqualityModule::trackingMultiplyRow(RowIndex ridx, int sgn) {
+ Assert(rowIndexIsTracked(ridx));
Assert(sgn != 0);
- Assert(!d_tableau.isBasic(nb));
-
- //inf.setErrorsChange(0);
- //inf.setlimiting = NullConstraint;
-
-
- // Error variables moving in the correct direction
- Assert(d_relevantErrorBuffer.empty());
-
- // phases :
- enum ComputeSafePhase {
- NoBoundSelected,
- NbsBoundSelected,
- BasicBoundSelected,
- DegenerateBoundSelected
- } phase;
-
- phase = NoBoundSelected;
-
- static int instance = 0;
- Debug("computeSafeUpdate") << "computeSafeUpdate " << (++instance) << endl;
-
- if(sgn > 0 && d_variables.hasUpperBound(nb)){
- Constraint ub = d_variables.getUpperBoundConstraint(nb);
- inf.updatePureFocus(ub->getValue() - d_variables.getAssignment(nb), ub);
-
- Assert(inf.nonbasicDelta().sgn() == sgn);
- Debug("computeSafeUpdate") << "computeSafeUpdate " << inf.limiting() << endl;
- phase = NbsBoundSelected;
- }else if(sgn < 0 && d_variables.hasLowerBound(nb)){
- Constraint lb = d_variables.getLowerBoundConstraint(nb);
- inf.updatePureFocus(lb->getValue() - d_variables.getAssignment(nb), lb);
-
- Assert(inf.nonbasicDelta().sgn() == sgn);
-
- Debug("computeSafeUpdate") << "computeSafeUpdate " << inf.limiting() << endl;
- phase = NbsBoundSelected;
- }
-
- Tableau::ColIterator basicIter = d_tableau.colIterator(nb);
- for(; !basicIter.atEnd(); ++basicIter){
- const Tableau::Entry& entry = *basicIter;
- Assert(entry.getColVar() == nb);
-
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
- const Rational& a_ji = entry.getCoefficient();
- int basic_movement = sgn * a_ji.sgn();
-
- Debug("computeSafeUpdate")
- << "computeSafeUpdate: "
- << basic << ", "
- << basic_movement << ", "
- << d_variables.cmpAssignmentUpperBound(basic) << ", "
- << d_variables.cmpAssignmentLowerBound(basic) << ", "
- << a_ji << ", "
- << d_variables.getAssignment(basic) << endl;
-
- Constraint proposal = NullConstraint;
-
- if(basic_movement > 0){
- if(d_variables.cmpAssignmentLowerBound(basic) < 0){
- d_relevantErrorBuffer.push_back(&entry);
- }
- if(d_variables.hasUpperBound(basic) &&
- d_variables.cmpAssignmentUpperBound(basic) <= 0){
- proposal = d_variables.getUpperBoundConstraint(basic);
- }
- }else if(basic_movement < 0){
- if(d_variables.cmpAssignmentUpperBound(basic) > 0){
- d_relevantErrorBuffer.push_back(&entry);
- }
- if(d_variables.hasLowerBound(basic) &&
- d_variables.cmpAssignmentLowerBound(basic) >= 0){
- proposal = d_variables.getLowerBoundConstraint(basic);
- }
- }
- if(proposal != NullConstraint){
- const Rational& coeff = entry.getCoefficient();
- DeltaRational diff = proposal->getValue() - d_variables.getAssignment(basic);
- diff /= coeff;
- int cmp = phase == NoBoundSelected ? 0 : diff.cmp(inf.nonbasicDelta());
- Assert(diff.sgn() == sgn || diff.sgn() == 0);
- bool prefer = false;
- switch(phase){
- case NoBoundSelected:
- prefer = true;
- break;
- case NbsBoundSelected:
- prefer = (sgn > 0 && cmp < 0 ) || (sgn < 0 && cmp > 0);
- break;
- case BasicBoundSelected:
- prefer =
- (sgn > 0 && cmp < 0 ) ||
- (sgn < 0 && cmp > 0) ||
- (cmp == 0 && basic == (this->*pref)(basic, inf.leaving()));
- break;
- case DegenerateBoundSelected:
- prefer = cmp == 0 && basic == (this->*pref)(basic, inf.leaving());
- break;
- }
- if(prefer){
- inf.updatePivot(diff, coeff, proposal);
-
- phase = (diff.sgn() != 0) ? BasicBoundSelected : DegenerateBoundSelected;
- }
- }
+ if(sgn < 0){
+ BoundsInfo& bi = d_btracking.get(ridx);
+ bi = bi.multiplyBySgn(sgn);
}
-
- if(phase == DegenerateBoundSelected){
- inf.setErrorsChange(0);
- }else{
- computedFixed(inf);
- }
- inf.determineFocusDirection();
-
- d_relevantErrorBuffer.clear();
}
-void LinearEqualityModule::computedFixed(UpdateInfo& proposal){
- Assert(proposal.nonbasicDirection() != 0);
- Assert(!d_tableau.isBasic(proposal.nonbasic()));
-
- //bool unconstrained = (proposal.d_limiting == NullConstraint);
-
- Assert(!proposal.unbounded() || !d_relevantErrorBuffer.empty());
-
- Assert(proposal.unbounded() ||
- proposal.nonbasicDelta().sgn() == proposal.nonbasicDirection());
-
- // proposal.d_value is the max
-
- UpdateInfo max;
- int dropped = 0;
- //Constraint maxFix = NullConstraint;
- //DeltaRational maxAmount;
-
- EntryPointerVector::const_iterator i = d_relevantErrorBuffer.begin();
- EntryPointerVector::const_iterator i_end = d_relevantErrorBuffer.end();
- for(; i != i_end; ++i){
- const Tableau::Entry& entry = *(*i);
- Assert(entry.getColVar() == proposal.nonbasic());
-
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
- const Rational& a_ji = entry.getCoefficient();
- int basic_movement = proposal.nonbasicDirection() * a_ji.sgn();
-
- DeltaRational theta;
- DeltaRational proposedValue;
- if(!proposal.unbounded()){
- theta = proposal.nonbasicDelta() * a_ji;
- proposedValue = theta + d_variables.getAssignment(basic);
- }
-
- Constraint fixed = NullConstraint;
-
- if(basic_movement < 0){
- Assert(d_variables.cmpAssignmentUpperBound(basic) > 0);
-
- if(proposal.unbounded() || d_variables.cmpToUpperBound(basic, proposedValue) <= 0){
- --dropped;
- fixed = d_variables.getUpperBoundConstraint(basic);
- }
- }else if(basic_movement > 0){
- Assert(d_variables.cmpAssignmentLowerBound(basic) < 0);
+void LinearEqualityModule::trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn){
+ Assert(oldSgn != currSgn);
+ BoundsInfo nb_inf = d_variables.boundsInfo(nb);
- if(proposal.unbounded() || d_variables.cmpToLowerBound(basic, proposedValue) >= 0){
- --dropped;
- fixed = d_variables.getLowerBoundConstraint(basic);
- }
- }
- if(fixed != NullConstraint){
- DeltaRational amount = fixed->getValue() - d_variables.getAssignment(basic);
- amount /= a_ji;
- Assert(amount.sgn() == proposal.nonbasicDirection());
-
- if(max.uninitialized()){
- max = UpdateInfo(proposal.nonbasic(), proposal.nonbasicDirection());
- max.updatePivot(amount, a_ji, fixed, dropped);
- }else{
- int cmp = amount.cmp(max.nonbasicDelta());
- bool prefer =
- (proposal.nonbasicDirection() < 0 && cmp < 0) ||
- (proposal.nonbasicDirection() > 0 && cmp > 0) ||
- (cmp == 0 && fixed->getVariable() < max.limiting()->getVariable());
-
- if(prefer){
- max.updatePivot(amount, a_ji, fixed, dropped);
- }else{
- max.setErrorsChange(dropped);
- }
- }
- }
- }
- Assert(dropped < 0 || !proposal.unbounded());
+ Assert(rowIndexIsTracked(ridx));
- if(dropped < 0){
- proposal = max;
- }else{
- Assert(dropped == 0);
- Assert(proposal.nonbasicDelta().sgn() != 0);
- Assert(proposal.nonbasicDirection() != 0);
- proposal.setErrorsChange(0);
- }
- Assert(proposal.errorsChange() == dropped);
+ BoundsInfo& row_bi = d_btracking.get(ridx);
+ row_bi.addInSgn(nb_inf, oldSgn, currSgn);
}
ArithVar LinearEqualityModule::minBy(const ArithVarVec& vec, VarPreferenceFunction pf) const{
@@ -1188,8 +956,9 @@ bool LinearEqualityModule::willBeInConflictAfterPivot(const Tableau::Entry& entr
// Assume past this point, nb will be in error if this pivot is done
ArithVar nb = entry.getColVar();
- ArithVar basic = d_tableau.rowIndexToBasic(entry.getRowIndex());
- Assert(basicIsTracked(basic));
+ RowIndex ridx = entry.getRowIndex();
+ ArithVar basic = d_tableau.rowIndexToBasic(ridx);
+ Assert(rowIndexIsTracked(ridx));
int coeffSgn = entry.getCoefficient().sgn();
@@ -1201,12 +970,11 @@ bool LinearEqualityModule::willBeInConflictAfterPivot(const Tableau::Entry& entr
// 2) -a * x = -y + \sum b * z
// 3) x = (-1/a) * ( -y + \sum b * z)
- Assert(basicIsTracked(basic));
- BoundCounts bc = d_boundTracking[basic];
+ BoundCounts bc = d_btracking[ridx].atBounds();
// 1) y = a * x + \sum b * z
// Get bc(\sum b * z)
- BoundCounts sumOnly = bc - d_variables.boundCounts(nb).multiplyBySgn(coeffSgn);
+ BoundCounts sumOnly = bc - d_variables.atBoundCounts(nb).multiplyBySgn(coeffSgn);
// y's bounds in the proposed model
int yWillBeAtUb = (bToUB || d_variables.boundsAreEqual(basic)) ? 1 : 0;
@@ -1215,19 +983,19 @@ bool LinearEqualityModule::willBeInConflictAfterPivot(const Tableau::Entry& entr
// 2) -a * x = -y + \sum b * z
// Get bc(-y + \sum b * z)
- BoundCounts withNegY = sumOnly + ysBounds.multiplyBySgn(-1);
+ sumOnly.addInChange(-1, d_variables.atBoundCounts(basic), ysBounds);
// 3) x = (-1/a) * ( -y + \sum b * z)
// Get bc((-1/a) * ( -y + \sum b * z))
- BoundCounts xsBoundsAfterPivot = withNegY.multiplyBySgn(-coeffSgn);
+ BoundCounts xsBoundsAfterPivot = sumOnly.multiplyBySgn(-coeffSgn);
uint32_t length = d_tableau.basicRowLength(basic);
if(nbSgn > 0){
// Only check for the upper bound being violated
- return xsBoundsAfterPivot.atLowerBounds() + 1 == length;
+ return xsBoundsAfterPivot.lowerBoundCount() + 1 == length;
}else{
// Only check for the lower bound being violated
- return xsBoundsAfterPivot.atUpperBounds() + 1 == length;
+ return xsBoundsAfterPivot.upperBoundCount() + 1 == length;
}
}
diff --git a/src/theory/arith/linear_equality.h b/src/theory/arith/linear_equality.h
index 8b9b888f2..293a0ddad 100644
--- a/src/theory/arith/linear_equality.h
+++ b/src/theory/arith/linear_equality.h
@@ -192,9 +192,6 @@ public:
};
-
-
-
class LinearEqualityModule {
public:
typedef ArithVar (LinearEqualityModule::*VarPreferenceFunction)(ArithVar, ArithVar) const;
@@ -226,14 +223,12 @@ public:
* Initializes a LinearEqualityModule with a partial model, a tableau,
* and a callback function for when basic variables update their values.
*/
- LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundCountingVector& boundTracking, BasicVarModelUpdateCallBack f);
+ LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundInfoMap& boundTracking, BasicVarModelUpdateCallBack f);
/**
* Updates the assignment of a nonbasic variable x_i to v.
* Also updates the assignment of basic variables accordingly.
*/
- void updateUntracked(ArithVar x_i, const DeltaRational& v);
- void updateTracked(ArithVar x_i, const DeltaRational& v);
void update(ArithVar x_i, const DeltaRational& v){
if(d_areTracking){
updateTracked(x_i,v);
@@ -241,7 +236,13 @@ public:
updateUntracked(x_i,v);
}
}
- void updateMany(const DenseMap<DeltaRational>& many);
+
+ /** Specialization of update if the module is not tracking yet (for Assert*). */
+ void updateUntracked(ArithVar x_i, const DeltaRational& v);
+
+ /** Specialization of update if the module is not tracking yet (for Simplex). */
+ void updateTracked(ArithVar x_i, const DeltaRational& v);
+
/**
* Updates the value of a basic variable x_i to v,
@@ -249,28 +250,34 @@ public:
* Updates the assignment of the other basic variables accordingly.
*/
void pivotAndUpdate(ArithVar x_i, ArithVar x_j, const DeltaRational& v);
- //void pivotAndUpdateAdj(ArithVar x_i, ArithVar x_j, const DeltaRational& v);
ArithVariables& getVariables() const{ return d_variables; }
Tableau& getTableau() const{ return d_tableau; }
+ /**
+ * Updates every non-basic to reflect the assignment in many.
+ * For use with ApproximateSimplex.
+ */
+ void updateMany(const DenseMap<DeltaRational>& many);
void forceNewBasis(const DenseSet& newBasis);
+ void applySolution(const DenseSet& newBasis, const DenseMap<DeltaRational>& newValues);
+
+
+ /**
+ * Returns a pointer to the first Tableau entry on the row ridx that does not
+ * have an either a lower bound/upper bound for proving a bound on skip.
+ * The variable skip is always excluded. Returns NULL if there is no such element.
+ *
+ * If skip == ARITHVAR_SENTINEL, this is equivalent to considering the whole row.
+ */
+ const Tableau::Entry* rowLacksBound(RowIndex ridx, bool upperBound, ArithVar skip);
- bool hasBounds(ArithVar basic, bool upperBound);
- bool hasLowerBounds(ArithVar basic){
- return hasBounds(basic, false);
- }
- bool hasUpperBounds(ArithVar basic){
- return hasBounds(basic, true);
- }
void startTrackingBoundCounts();
void stopTrackingBoundCounts();
- void includeBoundCountChange(ArithVar nb, BoundCounts prev);
-
- void computeSafeUpdate(UpdateInfo& inf, VarPreferenceFunction basic);
+ void includeBoundUpdate(ArithVar nb, const BoundsInfo& prev);
uint32_t updateProduct(const UpdateInfo& inf) const;
@@ -334,40 +341,6 @@ public:
}
}
- // template<bool heuristic>
- // bool preferNonDegenerate(const UpdateInfo& a, const UpdateInfo& b) const{
- // if(a.focusDirection() == b.focusDirection()){
- // if(heuristic){
- // return preferNeitherBound(a,b);
- // }else{
- // return minNonBasicVarOrder(a,b);
- // }
- // }else{
- // return a.focusDirection() < b.focusDirection();
- // }
- // }
-
- // template <bool heuristic>
- // bool preferErrorsFixed(const UpdateInfo& a, const UpdateInfo& b) const{
- // if( a.errorsChange() == b.errorsChange() ){
- // return preferNonDegenerate<heuristic>(a,b);
- // }else{
- // return a.errorsChange() > b.errorsChange();
- // }
- // }
-
- // template <bool heuristic>
- // bool preferConflictFound(const UpdateInfo& a, const UpdateInfo& b) const{
- // if(a.d_foundConflict && b.d_foundConflict){
- // // if both are true, determinize the preference
- // return minNonBasicVarOrder(a,b);
- // }else if( a.d_foundConflict || b.d_foundConflict ){
- // return b.d_foundConflict;
- // }else{
- // return preferErrorsFixed<heuristic>(a,b);
- // }
- // }
-
bool modifiedBlands(const UpdateInfo& a, const UpdateInfo& b) const {
Assert(a.focusDirection() == 0 && b.focusDirection() == 0);
Assert(a.describesPivot());
@@ -427,31 +400,27 @@ public:
}
private:
- typedef std::vector<const Tableau::Entry*> EntryPointerVector;
- EntryPointerVector d_relevantErrorBuffer;
-
- //uint32_t computeUnconstrainedUpdate(ArithVar nb, int sgn, DeltaRational& am);
- //uint32_t computedFixed(ArithVar nb, int sgn, const DeltaRational& am);
- void computedFixed(UpdateInfo&);
- // RowIndex -> BoundCount
- BoundCountingVector& d_boundTracking;
+ /**
+ * This maps each row index to its relevant bounds info.
+ * This tracks the count for how many variables on a row have bounds
+ * and how many are assigned at their bounds.
+ */
+ BoundInfoMap& d_btracking;
bool d_areTracking;
+public:
+ /**
+ * The constraint on a basic variable b is implied by the constraints
+ * on its row. This is a wrapper for propagateRow().
+ */
+ void propagateBasicFromRow(Constraint c);
+
/**
* Exports either the explanation of an upperbound or a lower bound
* of the basic variable basic, using the non-basic variables in the row.
*/
- template <bool upperBound>
- void propagateNonbasics(ArithVar basic, Constraint c);
-
-public:
- void propagateNonbasicsLowerBound(ArithVar basic, Constraint c){
- propagateNonbasics<false>(basic, c);
- }
- void propagateNonbasicsUpperBound(ArithVar basic, Constraint c){
- propagateNonbasics<true>(basic, c);
- }
+ void propagateRow(std::vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c);
/**
* Computes the value of a basic variable using the assignments
@@ -460,14 +429,7 @@ public:
* - the the current assignment (useSafe=false) or
* - the safe assignment (useSafe = true).
*/
- DeltaRational computeRowValue(ArithVar x, bool useSafe);
-
- inline DeltaRational computeLowerBound(ArithVar basic){
- return computeBound(basic, false);
- }
- inline DeltaRational computeUpperBound(ArithVar basic){
- return computeBound(basic, true);
- }
+ DeltaRational computeRowValue(ArithVar x, bool useSafe) const;
/**
* A PreferenceFunction takes a const ref to the SimplexDecisionProcedure,
@@ -548,41 +510,64 @@ public:
const Tableau::Entry* selectSlackEntry(ArithVar x_i, bool above) const;
+ inline bool rowIndexIsTracked(RowIndex ridx) const {
+ return d_btracking.isKey(ridx);
+ }
inline bool basicIsTracked(ArithVar v) const {
- return d_boundTracking.isKey(v);
+ return rowIndexIsTracked(d_tableau.basicToRowIndex(v));
}
- void trackVariable(ArithVar x_i);
-
- void maybeRemoveTracking(ArithVar v){
- Assert(!d_tableau.isBasic(v));
- if(d_boundTracking.isKey(v)){
- d_boundTracking.remove(v);
- }
+ void trackRowIndex(RowIndex ridx);
+ void stopTrackingRowIndex(RowIndex ridx){
+ Assert(rowIndexIsTracked(ridx));
+ d_btracking.remove(ridx);
}
- // void trackVariable(ArithVar x_i){
- // Assert(!basicIsTracked(x_i));
- // d_boundTracking.set(x_i,computeBoundCounts(x_i));
- // }
+ /**
+ * If the pivot described in u were performed,
+ * then the row would qualify as being either at the minimum/maximum
+ * to the non-basics being at their bounds.
+ * The minimum/maximum is determined by the direction the non-basic is changing.
+ */
bool basicsAtBounds(const UpdateInfo& u) const;
+
private:
- BoundCounts computeBoundCounts(ArithVar x_i) const;
+
+ /**
+ * Recomputes the bound info for a row using either the information
+ * in the bounds queue or the current information.
+ * O(row length of ridx)
+ */
+ BoundsInfo computeRowBoundInfo(RowIndex ridx, bool inQueue) const;
+
public:
- //BoundCounts cachingCountBounds(ArithVar x_i) const;
- BoundCounts _countBounds(ArithVar x_i) const;
+ /** Debug only routine. */
+ BoundCounts debugBasicAtBoundCount(ArithVar x_i) const;
+
+ /** Track the effect of the change of coefficient for bound counting. */
void trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn);
- void trackingSwap(ArithVar basic, ArithVar nb, int sgn);
+ /** Track the effect of multiplying a row by a sign for bound counting. */
+ void trackingMultiplyRow(RowIndex ridx, int sgn);
+
+ /** Count for how many on a row have *an* upper/lower bounds. */
+ BoundCounts hasBoundCount(RowIndex ri) const {
+ Assert(d_variables.boundsQueueEmpty());
+ return d_btracking[ri].hasBounds();
+ }
+ /**
+ * Are there any non-basics on x_i's row that are not at
+ * their respective lower bounds (mod sgns).
+ * O(1) time due to the atBound() count.
+ */
bool nonbasicsAtLowerBounds(ArithVar x_i) const;
- bool nonbasicsAtUpperBounds(ArithVar x_i) const;
- ArithVar _anySlackLowerBound(ArithVar x_i) const {
- return selectSlack<true>(x_i, &LinearEqualityModule::noPreference);
- }
- ArithVar _anySlackUpperBound(ArithVar x_i) const {
- return selectSlack<false>(x_i, &LinearEqualityModule::noPreference);
- }
+ /**
+ * Are there any non-basics on x_i's row that are not at
+ * their respective upper bounds (mod sgns).
+ * O(1) time due to the atBound() count.
+ */
+ bool nonbasicsAtUpperBounds(ArithVar x_i) const;
private:
class TrackingCallback : public CoefficientChangeCallback {
@@ -593,8 +578,8 @@ private:
void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn){
d_linEq->trackingCoefficientChange(ridx, nb, oldSgn, currSgn);
}
- void swap(ArithVar basic, ArithVar nb, int oldNbSgn){
- d_linEq->trackingSwap(basic, nb, oldNbSgn);
+ void multiplyRow(RowIndex ridx, int sgn){
+ d_linEq->trackingMultiplyRow(ridx, sgn);
}
bool canUseRow(RowIndex ridx) const {
ArithVar basic = d_linEq->getTableau().rowIndexToBasic(ridx);
@@ -629,8 +614,11 @@ public:
return minimallyWeakConflict(false, conflictVar);
}
-private:
- DeltaRational computeBound(ArithVar basic, bool upperBound);
+ /**
+ * Computes the sum of the upper/lower bound of row.
+ * The variable skip is not included in the sum.
+ */
+ DeltaRational computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const;
public:
void substitutePlusTimesConstant(ArithVar to, ArithVar from, const Rational& mult);
@@ -703,6 +691,7 @@ private:
IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings;
TimerStat d_weakenTime;
+ TimerStat d_forceTime;
Statistics();
~Statistics();
@@ -737,13 +726,13 @@ public:
}
};
-class UpdateTrackingCallback : public BoundCountsCallback {
+class UpdateTrackingCallback : public BoundUpdateCallback {
private:
LinearEqualityModule* d_mod;
public:
UpdateTrackingCallback(LinearEqualityModule* mod): d_mod(mod){}
- void operator()(ArithVar v, BoundCounts bc){
- d_mod->includeBoundCountChange(v, bc);
+ void operator()(ArithVar v, const BoundsInfo& bi){
+ d_mod->includeBoundUpdate(v, bi);
}
};
diff --git a/src/theory/arith/matrix.cpp b/src/theory/arith/matrix.cpp
index 7136c3fa8..b8bd68488 100644
--- a/src/theory/arith/matrix.cpp
+++ b/src/theory/arith/matrix.cpp
@@ -24,7 +24,7 @@ namespace theory {
namespace arith {
void NoEffectCCCB::update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) {}
-void NoEffectCCCB::swap(ArithVar basic, ArithVar nb, int nbSgn){}
+void NoEffectCCCB::multiplyRow(RowIndex ridx, int sgn){}
bool NoEffectCCCB::canUseRow(RowIndex ridx) const { return false; }
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/matrix.h b/src/theory/arith/matrix.h
index 100f999e0..d93b6986e 100644
--- a/src/theory/arith/matrix.h
+++ b/src/theory/arith/matrix.h
@@ -39,15 +39,15 @@ const RowIndex ROW_INDEX_SENTINEL = std::numeric_limits<RowIndex>::max();
class CoefficientChangeCallback {
public:
- virtual void update(RowIndex basic, ArithVar nb, int oldSgn, int currSgn) = 0;
- virtual void swap(ArithVar basic, ArithVar nb, int nbSgn) = 0;
+ virtual void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) = 0;
+ virtual void multiplyRow(RowIndex ridx, int Sgn) = 0;
virtual bool canUseRow(RowIndex ridx) const = 0;
};
class NoEffectCCCB : public CoefficientChangeCallback {
public:
void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn);
- void swap(ArithVar basic, ArithVar nb, int nbSgn);
+ void multiplyRow(RowIndex ridx, int Sgn);
bool canUseRow(RowIndex ridx) const;
};
diff --git a/src/theory/arith/normal_form.cpp b/src/theory/arith/normal_form.cpp
index 8454ca210..7cd202e53 100644
--- a/src/theory/arith/normal_form.cpp
+++ b/src/theory/arith/normal_form.cpp
@@ -22,7 +22,7 @@
using namespace std;
namespace CVC4 {
-namespace theory{
+namespace theory {
namespace arith {
bool Variable::isDivMember(Node n){
@@ -745,9 +745,8 @@ bool Comparison::isNormalGEQ() const {
return false;
}else{
if(left.isIntegral()){
- return left.denominatorLCMIsOne() && left.numeratorGCDIsOne();
+ return left.signNormalizedReducedSum();
}else{
- Debug("nf::tmp") << "imme sdfhkdjfh "<< left.leadingCoefficientIsAbsOne() << endl;
return left.leadingCoefficientIsAbsOne();
}
}
@@ -768,7 +767,7 @@ bool Comparison::isNormalLT() const {
return false;
}else{
if(left.isIntegral()){
- return left.denominatorLCMIsOne() && left.numeratorGCDIsOne();
+ return left.signNormalizedReducedSum();
}else{
return left.leadingCoefficientIsAbsOne();
}
@@ -889,6 +888,7 @@ Node Comparison::mkIntInequality(Kind k, const Polynomial& p){
Polynomial left = sp.getPolynomial();
Rational right = - (sp.getConstant().getValue());
+
Monomial m = left.getHead();
Assert(!m.isConstant());
@@ -899,16 +899,31 @@ Node Comparison::mkIntInequality(Kind k, const Polynomial& p){
Polynomial newLeft = left * mult;
Rational rightMult = right * mult;
+ bool negateResult = false;
+ if(!newLeft.leadingCoefficientIsPositive()){
+ // multiply by -1
+ // a: left >= right or b: left > right
+ // becomes
+ // a: -left <= -right or b: -left < -right
+ // a: not (-left > -right) or b: (not -left >= -right)
+ newLeft = -newLeft;
+ rightMult = -rightMult;
+ k = (kind::GT == k) ? kind::GEQ : kind::GT;
+ negateResult = true;
+ // the later stages handle:
+ // a: not (-left >= -right + 1) or b: (not -left >= -right)
+ }
+ Node result = Node::null();
if(rightMult.isIntegral()){
if(k == kind::GT){
// (> p z)
// (>= p (+ z 1))
Constant rightMultPlusOne = Constant::mkConstant(rightMult + 1);
- return toNode(kind::GEQ, newLeft, rightMultPlusOne);
+ result = toNode(kind::GEQ, newLeft, rightMultPlusOne);
}else{
Constant newRight = Constant::mkConstant(rightMult);
- return toNode(kind::GEQ, newLeft, newRight);
+ result = toNode(kind::GEQ, newLeft, newRight);
}
}else{
//(>= l (/ n d))
@@ -916,7 +931,13 @@ Node Comparison::mkIntInequality(Kind k, const Polynomial& p){
//This also hold for GT as (ceil (/ n d)) > (/ n d)
Integer ceilr = rightMult.ceiling();
Constant ceilRight = Constant::mkConstant(ceilr);
- return toNode(kind::GEQ, newLeft, ceilRight);
+ result = toNode(kind::GEQ, newLeft, ceilRight);
+ }
+ Assert(!result.isNull());
+ if(negateResult){
+ return result.notNode();
+ }else{
+ return result;
}
}
diff --git a/src/theory/arith/normal_form.h b/src/theory/arith/normal_form.h
index bcf9cbfa4..1dddb5a5b 100644
--- a/src/theory/arith/normal_form.h
+++ b/src/theory/arith/normal_form.h
@@ -76,12 +76,13 @@ namespace arith {
* (exists realMonomial (monomialList qpolynomial))
* abs(monomialCoefficient (head (monomialList qpolynomial))) == 1
*
- * integer_cmp := (<= zpolynomial constant)
+ * integer_cmp := (>= zpolynomial constant)
* where
* not (exists constantMonomial (monomialList zpolynomial))
* (forall integerMonomial (monomialList zpolynomial))
* the gcd of all numerators of coefficients is 1
* the denominator of all coefficients and the constant is 1
+ * the leading coefficient is positive
*
* rational_eq := (= qvarlist qpolynomial)
* where
@@ -240,6 +241,11 @@ public:
case kind::INTS_MODULUS_TOTAL:
case kind::DIVISION_TOTAL:
return isDivMember(n);
+ case kind::ABS:
+ case kind::TO_INTEGER:
+ // Treat to_int as a variable; it is replaced in early preprocessing
+ // by a variable.
+ return true;
default:
return (!isRelationOperator(k)) &&
(Theory::isLeafOf(n, theory::THEORY_ARITH));
@@ -939,6 +945,10 @@ public:
bool denominatorLCMIsOne() const;
bool numeratorGCDIsOne() const;
+ bool signNormalizedReducedSum() const {
+ return leadingCoefficientIsPositive() && denominatorLCMIsOne() && numeratorGCDIsOne();
+ }
+
/**
* Returns the Least Common Multiple of the denominators of the coefficients
* of the monomials.
@@ -1265,7 +1275,7 @@ private:
* Creates a comparison equivalent to (k l 0).
* k is either GT or GEQ.
* It is not the case that all variables in l are integral.
- */
+ */
static Node mkRatInequality(Kind k, const Polynomial& l);
public:
diff --git a/src/theory/arith/options b/src/theory/arith/options
index 977d6cb32..43b582bc8 100644
--- a/src/theory/arith/options
+++ b/src/theory/arith/options
@@ -56,7 +56,7 @@ option arithMLTrick miplib-trick --enable-miplib-trick/--disable-miplib-trick bo
turns on the preprocessing step of attempting to infer bounds on miplib problems
/turns off the preprocessing step of attempting to infer bounds on miplib problems
-option arithMLTrickSubstitutions miplib-trick-subs --miplib-trick-subs unsigned :default 1
+option arithMLTrickSubstitutions miplib-trick-subs --miplib-trick-subs=N unsigned :default 1
do substitution for miplib 'tmp' vars if defined in <= N eliminated vars
option doCutAllBounded --cut-all-bounded bool :default false :read-write
@@ -67,11 +67,11 @@ option maxCutsInContext --maxCutsInContext unsigned :default 65535
maximum cuts in a given context before signalling a restart
option revertArithModels --revert-arith-models-on-unsat bool :default false
- Revert the arithmetic model to a known safe model on unsat if one is cached
+ revert the arithmetic model to a known safe model on unsat if one is cached
option havePenalties --fc-penalties bool :default false :read-write
turns on degenerate pivot penalties
-/ turns off degenerate pivot penalties
+/turns off degenerate pivot penalties
option useFC --use-fcsimplex bool :default false :read-write
use focusing and converging simplex (FMCAD 2013 submission)
@@ -80,15 +80,27 @@ option useSOI --use-soi bool :default false :read-write
use sum of infeasibility simplex (FMCAD 2013 submission)
option restrictedPivots --restrict-pivots bool :default true :read-write
- have a pivot cap for simplex at effort levels below fullEffort.
+ have a pivot cap for simplex at effort levels below fullEffort
option collectPivots --collect-pivot-stats bool :default false :read-write
collect the pivot history
option fancyFinal --fancy-final bool :default false :read-write
- Tuning how final check works for really hard problems.
+ tuning how final check works for really hard problems
option exportDioDecompositions --dio-decomps bool :default false :read-write
- Let skolem variables for integer divisibility constraints leak from the dio solver.
+ let skolem variables for integer divisibility constraints leak from the dio solver
+
+option newProp --new-prop bool :default false :read-write
+ use the new row propagation system
+
+option arithPropAsLemmaLength --arith-prop-clauses uint16_t :default 8 :read-write
+ rows shorter than this are propagated as clauses
+
+option soiQuickExplain --soi-qe bool :default false :read-write
+ use quick explain to minimize the sum of infeasibility conflicts
+
+option rewriteDivk rewrite-divk --rewrite-divk bool :default false
+ rewrite division and mod when by a constant into linear terms
endmodule
diff --git a/src/theory/arith/partial_model.cpp b/src/theory/arith/partial_model.cpp
index 695d9df25..3fae3751c 100644
--- a/src/theory/arith/partial_model.cpp
+++ b/src/theory/arith/partial_model.cpp
@@ -35,12 +35,13 @@ ArithVariables::ArithVariables(context::Context* c, DeltaComputeCallback deltaCo
d_released(),
d_releasedIterator(d_released.begin()),
d_nodeToArithVarMap(),
+ d_boundsQueue(),
+ d_enqueueingBoundCounts(true),
d_lbRevertHistory(c, true, LowerBoundCleanUp(this)),
d_ubRevertHistory(c, true, UpperBoundCleanUp(this)),
d_deltaIsSafe(false),
d_delta(-1,1),
- d_deltaComputingFunc(deltaComputingFunc),
- d_enqueueingBoundCounts(true)
+ d_deltaComputingFunc(deltaComputingFunc)
{ }
ArithVariables::VarInfo::VarInfo()
@@ -55,6 +56,10 @@ ArithVariables::VarInfo::VarInfo()
d_slack(false)
{ }
+bool ArithVariables::VarInfo::initialized() const {
+ return d_var != ARITHVAR_SENTINEL;
+}
+
void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool slack){
Assert(!initialized());
Assert(d_lb == NullConstraint);
@@ -82,7 +87,7 @@ void ArithVariables::VarInfo::uninitialize(){
d_node = Node::null();
}
-bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundCounts & prev){
+bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundsInfo& prev){
Assert(initialized());
d_assignment = a;
int cmpUB = (d_ub == NullConstraint) ? -1 :
@@ -97,7 +102,7 @@ bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundCounts
(cmpUB == 0 || d_cmpAssignmentUB == 0);
if(lbChanged || ubChanged){
- prev = boundCounts();
+ prev = boundsInfo();
}
d_cmpAssignmentUB = cmpUB;
@@ -119,33 +124,59 @@ void ArithVariables::releaseArithVar(ArithVar v){
}
}
-bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundCounts& prev){
+bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundsInfo& prev){
Assert(initialized());
- d_ub = ub;
- int cmpUB = (d_ub == NullConstraint) ? -1 : d_assignment.cmp(d_ub->getValue());
- bool ubChanged = cmpUB != d_cmpAssignmentUB &&
- (cmpUB == 0 || d_cmpAssignmentUB == 0);
+ bool wasNull = d_ub == NullConstraint;
+ bool isNull = ub == NullConstraint;
+
+ int cmpUB = isNull ? -1 : d_assignment.cmp(ub->getValue());
+ bool ubChanged = (wasNull != isNull) ||
+ (cmpUB != d_cmpAssignmentUB && (cmpUB == 0 || d_cmpAssignmentUB == 0));
if(ubChanged){
- prev = boundCounts();
+ prev = boundsInfo();
}
+ d_ub = ub;
d_cmpAssignmentUB = cmpUB;
return ubChanged;
}
-bool ArithVariables::VarInfo::setLowerBound(Constraint lb, BoundCounts& prev){
+bool ArithVariables::VarInfo::setLowerBound(Constraint lb, BoundsInfo& prev){
Assert(initialized());
- d_lb = lb;
- int cmpLB = (d_lb == NullConstraint) ? 1 : d_assignment.cmp(d_lb->getValue());
+ bool wasNull = d_lb == NullConstraint;
+ bool isNull = lb == NullConstraint;
- bool lbChanged = cmpLB != d_cmpAssignmentLB &&
- (cmpLB == 0 || d_cmpAssignmentLB == 0);
+ int cmpLB = isNull ? 1 : d_assignment.cmp(lb->getValue());
+
+ bool lbChanged = (wasNull != isNull) ||
+ (cmpLB != d_cmpAssignmentLB && (cmpLB == 0 || d_cmpAssignmentLB == 0));
if(lbChanged){
- prev = boundCounts();
+ prev = boundsInfo();
}
+ d_lb = lb;
d_cmpAssignmentLB = cmpLB;
return lbChanged;
}
+BoundCounts ArithVariables::VarInfo::atBoundCounts() const {
+ uint32_t lbIndc = (d_cmpAssignmentLB == 0) ? 1 : 0;
+ uint32_t ubIndc = (d_cmpAssignmentUB == 0) ? 1 : 0;
+ return BoundCounts(lbIndc, ubIndc);
+}
+
+BoundCounts ArithVariables::VarInfo::hasBoundCounts() const {
+ uint32_t lbIndc = (d_lb != NullConstraint) ? 1 : 0;
+ uint32_t ubIndc = (d_ub != NullConstraint) ? 1 : 0;
+ return BoundCounts(lbIndc, ubIndc);
+}
+
+BoundsInfo ArithVariables::VarInfo::boundsInfo() const{
+ return BoundsInfo(atBoundCounts(), hasBoundCounts());
+}
+
+bool ArithVariables::VarInfo::canBeReclaimed() const{
+ return d_pushCount == 0;
+}
+
void ArithVariables::attemptToReclaimReleased(){
std::list<ArithVar>::iterator i_end = d_released.end();
for(int iter = 0; iter < 20 && d_releasedIterator != i_end; ++d_releasedIterator){
@@ -170,7 +201,7 @@ ArithVar ArithVariables::allocateVariable(){
attemptToReclaimReleased();
}
bool reclaim = !d_pool.empty();
-
+
ArithVar varX;
if(reclaim){
varX = d_pool.back();
@@ -210,7 +241,7 @@ void ArithVariables::setAssignment(ArithVar x, const DeltaRational& r){
}
invalidateDelta();
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setAssignment(r, prev)){
addToBoundQueue(x, prev);
}
@@ -229,7 +260,7 @@ void ArithVariables::setAssignment(ArithVar x, const DeltaRational& safe, const
invalidateDelta();
VarInfo& vi = d_vars.get(x);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setAssignment(r, prev)){
addToBoundQueue(x, prev);
}
@@ -314,7 +345,7 @@ void ArithVariables::setLowerBoundConstraint(Constraint c){
invalidateDelta();
VarInfo& vi = d_vars.get(x);
pushLowerBound(vi);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setLowerBound(c, prev)){
addToBoundQueue(x, prev);
}
@@ -333,37 +364,12 @@ void ArithVariables::setUpperBoundConstraint(Constraint c){
invalidateDelta();
VarInfo& vi = d_vars.get(x);
pushUpperBound(vi);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setUpperBound(c, prev)){
addToBoundQueue(x, prev);
}
}
-// void ArithVariables::forceRelaxLowerBound(ArithVar v){
-// AssertArgument(inMaps(v), "Calling forceRelaxLowerBound on a variable that is not properly setup.");
-// AssertArgument(hasLowerBound(v), "Calling forceRelaxLowerBound on a variable without a lowerbound.");
-
-// Debug("partial_model") << "forceRelaxLowerBound(" << v << ") dropping :" << getLowerBoundConstraint(v) << endl;
-
-// invalidateDelta();
-// VarInfo& vi = d_vars.get(v);
-// pushLowerBound(vi);
-// vi.setLowerBound(NullConstraint);
-// }
-
-
-// void ArithVariables::forceRelaxUpperBound(ArithVar v){
-// AssertArgument(inMaps(v), "Calling forceRelaxUpperBound on a variable that is not properly setup.");
-// AssertArgument(hasUpperBound(v), "Calling forceRelaxUpperBound on a variable without an upper bound.");
-
-// Debug("partial_model") << "forceRelaxUpperBound(" << v << ") dropping :" << getUpperBoundConstraint(v) << endl;
-
-// invalidateDelta();
-// VarInfo& vi = d_vars.get(v);
-// pushUpperBound(vi);
-// vi.setUpperBound(NullConstraint);
-// }
-
int ArithVariables::cmpToLowerBound(ArithVar x, const DeltaRational& c) const{
if(!hasLowerBound(x)){
// l = -\intfy
@@ -405,30 +411,16 @@ bool ArithVariables::hasEitherBound(ArithVar x) const{
bool ArithVariables::strictlyBelowUpperBound(ArithVar x) const{
return d_vars[x].d_cmpAssignmentUB < 0;
- // if(!hasUpperBound(x)){ // u = \infty
- // return true;
- // }else{
- // return d_assignment[x] < getUpperBound(x);
- // }
}
bool ArithVariables::strictlyAboveLowerBound(ArithVar x) const{
return d_vars[x].d_cmpAssignmentLB > 0;
- // if(!hasLowerBound(x)){ // l = -\infty
- // return true;
- // }else{
- // return getLowerBound(x) < d_assignment[x];
- // }
}
bool ArithVariables::assignmentIsConsistent(ArithVar x) const{
return
d_vars[x].d_cmpAssignmentLB >= 0 &&
d_vars[x].d_cmpAssignmentUB <= 0;
- // const DeltaRational& beta = getAssignment(x);
-
- // //l_i <= beta(x_i) <= u_i
- // return greaterThanLowerBound(x,beta) && lessThanUpperBound(x,beta);
}
@@ -442,7 +434,7 @@ void ArithVariables::clearSafeAssignments(bool revert){
ArithVar atBack = d_safeAssignment.back();
if(revert){
VarInfo& vi = d_vars.get(atBack);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setAssignment(d_safeAssignment[atBack], prev)){
addToBoundQueue(atBack, prev);
}
@@ -489,33 +481,6 @@ void ArithVariables::printModel(ArithVar x) const{
printModel(x, Debug("model"));
}
-// BoundRelationship ArithVariables::boundRelationship(Constraint lb, const DeltaRational& d, Constraint ub){
-// if(lb == NullConstraint && ub == NullConstraint){
-// return BetweenBounds;
-// }else if(lb == NullConstraint){
-// int cmp = d.cmp(ub->getValue());
-// return (cmp < 0) ? BetweenBounds :
-// (cmp == 0 ? AtUpperBound : AboveUpperBound);
-// }else if(ub == NullConstraint){
-// int cmp = d.cmp(lb->getValue());
-// return (cmp > 0) ? BetweenBounds :
-// (cmp == 0 ? AtLowerBound : BelowLowerBound);
-// }else{
-// Assert(lb->getValue() <= ub->getValue());
-// int cmpToLB = d.cmp(lb->getValue());
-// if(cmpToLB < 0){
-// return BelowLowerBound;
-// }else if(cmpToLB == 0){
-// return (d == ub->getValue()) ? AtBothBounds : AtLowerBound;
-// }else{
-// // d > 0
-// int cmpToUB = d.cmp(ub->getValue());
-// return (cmpToUB > 0) ? BetweenBounds :
-// (cmpToUB == 0 ? AtLowerBound : BelowLowerBound);
-// }
-// }
-// }
-
void ArithVariables::pushUpperBound(VarInfo& vi){
++vi.d_pushCount;
d_ubRevertHistory.push_back(make_pair(vi.d_var, vi.d_ub));
@@ -528,7 +493,7 @@ void ArithVariables::pushLowerBound(VarInfo& vi){
void ArithVariables::popUpperBound(AVCPair* c){
ArithVar x = c->first;
VarInfo& vi = d_vars.get(x);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setUpperBound(c->second, prev)){
addToBoundQueue(x, prev);
}
@@ -538,62 +503,42 @@ void ArithVariables::popUpperBound(AVCPair* c){
void ArithVariables::popLowerBound(AVCPair* c){
ArithVar x = c->first;
VarInfo& vi = d_vars.get(x);
- BoundCounts prev;
+ BoundsInfo prev;
if(vi.setLowerBound(c->second, prev)){
addToBoundQueue(x, prev);
}
--vi.d_pushCount;
}
-/* To ensure that the final deallocation stuff works,
- * we need to ensure that we need to not reference any of the other vectors
- */
-// void ArithVariables::relaxUpperBound(Constraint curr, Constraint afterPop){
-// BoundRelation next = Undefined;
-// switch(d_boundRel[x]){
-// case BelowLowerBound:
-// case BetweenBounds:
-// case AtLowerBound:
-// return; // do nothing
-// case AtUpperBound:
-// if(afterPop != NullConstraint
-// && curr->getValue() == afterPop->getValue()){
-// next = AtUpperBound;
-// }else{
-// next = BetweenBounds;
-// }
-// break;
-// case AtBothBounds:
-// if(afterPop != NullConstraint
-// && curr->getValue() == afterPop->getValue()){
-// next = AtUpperBound;
-// }else{
-// next = AtLowerBound;
-// }
-// break;
-// case AboveUpperBound:
-// if(afterPop == NullConstraint){
-// next = BetweenBounds;
-// }else{
-// int cmp = d_assignment[x].cmp(afterPop->getValue());
-// next = (cmp < 0) ? BetweenBounds :
-// (cmp == 0) ? AtUpperBound : AboveUpperBound;
-// }
-// break;
-// default:
-// Unreachable();
-// }
-// d_boundRel[x] = next;
-// }
+void ArithVariables::addToBoundQueue(ArithVar v, const BoundsInfo& prev){
+ if(d_enqueueingBoundCounts && !d_boundsQueue.isKey(v)){
+ d_boundsQueue.set(v, prev);
+ }
+}
+BoundsInfo ArithVariables::selectBoundsInfo(ArithVar v, bool old) const {
+ if(old && d_boundsQueue.isKey(v)){
+ return d_boundsQueue[v];
+ }else{
+ return boundsInfo(v);
+ }
+}
+bool ArithVariables::boundsQueueEmpty() const {
+ return d_boundsQueue.empty();
+}
-// void ArithVariables::relaxLowerBound(Constraint curr, Constraint afterPop){
-// // TODO this can be optimized using the automata induced by d_boundRel and
-// // the knowledge that lb <= ub
-// ArithVar x = curr->getVariable();
-// d_boundRel[x] = boundRelationship(afterPop, d_assignment[x], d_ubc[x]);
-// }
+void ArithVariables::processBoundsQueue(BoundUpdateCallback& changed){
+ while(!boundsQueueEmpty()){
+ ArithVar v = d_boundsQueue.back();
+ BoundsInfo prev = d_boundsQueue[v];
+ d_boundsQueue.pop_back();
+ BoundsInfo curr = boundsInfo(v);
+ if(prev != curr){
+ changed(v, prev);
+ }
+ }
+}
void ArithVariables::LowerBoundCleanUp::operator()(AVCPair* p){
d_pm->popLowerBound(p);
diff --git a/src/theory/arith/partial_model.h b/src/theory/arith/partial_model.h
index dcfe97079..deafb559a 100644
--- a/src/theory/arith/partial_model.h
+++ b/src/theory/arith/partial_model.h
@@ -44,6 +44,7 @@ namespace arith {
class ArithVariables {
private:
+
class VarInfo {
friend class ArithVariables;
ArithVar d_var;
@@ -62,29 +63,36 @@ private:
public:
VarInfo();
- bool setAssignment(const DeltaRational& r, BoundCounts& prev);
- bool setLowerBound(Constraint c, BoundCounts& prev);
- bool setUpperBound(Constraint c, BoundCounts& prev);
+ bool setAssignment(const DeltaRational& r, BoundsInfo& prev);
+ bool setLowerBound(Constraint c, BoundsInfo& prev);
+ bool setUpperBound(Constraint c, BoundsInfo& prev);
- bool initialized() const {
- return d_var != ARITHVAR_SENTINEL;
- }
+ /** Returns true if this VarInfo has been initialized. */
+ bool initialized() const;
+
+ /**
+ * Initializes the VarInfo with the ArithVar index it is associated with,
+ * the node that the variable represents, and whether it is a slack variable.
+ */
void initialize(ArithVar v, Node n, bool slack);
+ /** Uninitializes the VarInfo. */
void uninitialize();
- bool canBeReclaimed() const{
- return d_pushCount == 0;
- }
+ bool canBeReclaimed() const;
- BoundCounts boundCounts() const {
- uint32_t lbIndc = (d_cmpAssignmentLB == 0) ? 1 : 0;
- uint32_t ubIndc = (d_cmpAssignmentUB == 0) ? 1 : 0;
- return BoundCounts(lbIndc, ubIndc);
- }
+ /** Indicator variables for if the assignment is equal to the upper and lower bounds. */
+ BoundCounts atBoundCounts() const;
+
+ /** Combination of indicator variables for whether it has upper and lower bounds. */
+ BoundCounts hasBoundCounts() const;
+
+ /** Stores both atBoundCounts() and hasBoundCounts(). */
+ BoundsInfo boundsInfo() const;
};
- //Maps from ArithVar -> VarInfo
+ /**Maps from ArithVar -> VarInfo */
typedef DenseMap<VarInfo> VarInfoVec;
+ /** This maps an ArithVar to its Variable information.*/
VarInfoVec d_vars;
// Partial Map from Arithvar -> PreviousAssignment
@@ -104,7 +112,15 @@ private:
// Inverse of d_vars[x].d_node
NodeToArithVarMap d_nodeToArithVarMap;
- DenseMap<BoundCounts> d_atBoundsQueue;
+
+ /** The queue of constraints where the assignment is at the bound.*/
+ DenseMap<BoundsInfo> d_boundsQueue;
+
+ /**
+ * If this is true, record the incoming changes to the bound information.
+ * If this is false, the responsibility of recording the changes is LinearEqualities's.
+ */
+ bool d_enqueueingBoundCounts;
public:
@@ -188,6 +204,11 @@ private:
bool isSlack(ArithVar x) const {
return d_vars[x].d_slack;
}
+
+ bool integralAssignment(ArithVar x) const {
+ return getAssignment(x).isIntegral();
+ }
+
private:
typedef std::pair<ArithVar, Constraint> AVCPair;
@@ -225,7 +246,6 @@ private:
// Function to call if the value of delta needs to be recomputed.
DeltaComputeCallback d_deltaComputingFunc;
- bool d_enqueueingBoundCounts;
public:
@@ -252,22 +272,7 @@ public:
return d_vars[x].d_lb;
}
- /**
- * This forces the lower bound for a variable to be relaxed in the current context.
- * This is done by forcing the lower bound to be NullConstraint.
- * This is an expert only operation! (See primal simplex for an example.)
- */
- //void forceRelaxLowerBound(ArithVar x);
-
- /**
- * This forces the upper bound for a variable to be relaxed in the current context.
- * This is done by forcing the upper bound to be NullConstraint.
- * This is an expert only operation! (See primal simplex for an example.)
- */
- //void forceRelaxUpperBound(ArithVar x);
-
/* Initializes a variable to a safe value.*/
- //void initialize(ArithVar x, const DeltaRational& r);
void initialize(ArithVar x, Node n, bool slack);
ArithVar allocate(Node n, bool slack = false);
@@ -360,8 +365,14 @@ public:
return d_vars[x].d_cmpAssignmentUB;
}
- inline BoundCounts boundCounts(ArithVar x) const {
- return d_vars[x].boundCounts();
+ inline BoundCounts atBoundCounts(ArithVar x) const {
+ return d_vars[x].atBoundCounts();
+ }
+ inline BoundCounts hasBoundCounts(ArithVar x) const {
+ return d_vars[x].hasBoundCounts();
+ }
+ inline BoundsInfo boundsInfo(ArithVar x) const{
+ return d_vars[x].boundsInfo();
}
bool strictlyBelowUpperBound(ArithVar x) const;
@@ -391,38 +402,14 @@ public:
d_deltaIsSafe = true;
}
- // inline bool initialized(ArithVar x) const {
- // return d_vars[x].initialized();
- // }
-
- void addToBoundQueue(ArithVar v, BoundCounts prev){
- if(d_enqueueingBoundCounts && !d_atBoundsQueue.isKey(v)){
- d_atBoundsQueue.set(v, prev);
- }
- }
-
- BoundCounts oldBoundCounts(ArithVar v) const {
- if(d_atBoundsQueue.isKey(v)){
- return d_atBoundsQueue[v];
- }else{
- return boundCounts(v);
- }
- }
+ void startQueueingBoundCounts(){ d_enqueueingBoundCounts = true; }
+ void stopQueueingBoundCounts(){ d_enqueueingBoundCounts = false; }
+ void addToBoundQueue(ArithVar v, const BoundsInfo& prev);
- void startQueueingAtBoundQueue(){ d_enqueueingBoundCounts = true; }
- void stopQueueingAtBoundQueue(){ d_enqueueingBoundCounts = false; }
+ BoundsInfo selectBoundsInfo(ArithVar v, bool old) const;
- void processAtBoundQueue(BoundCountsCallback& changed){
- while(!d_atBoundsQueue.empty()){
- ArithVar v = d_atBoundsQueue.back();
- BoundCounts prev = d_atBoundsQueue[v];
- d_atBoundsQueue.pop_back();
- BoundCounts curr = boundCounts(v);
- if(prev != curr){
- changed(v, prev);
- }
- }
- }
+ bool boundsQueueEmpty() const;
+ void processBoundsQueue(BoundUpdateCallback& changed);
void printEntireModel(std::ostream& out) const;
diff --git a/src/theory/arith/pure_update_simplex.cpp b/src/theory/arith/pure_update_simplex.cpp
deleted file mode 100644
index 9b3edfa6f..000000000
--- a/src/theory/arith/pure_update_simplex.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/********************* */
-/*! \file simplex.cpp
- ** \verbatim
- ** Original author: taking
- ** Major contributors: none
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 New York University and The University of Iowa
- ** 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/arith/pure_update_simplex.h"
-#include "theory/arith/options.h"
-#include "theory/arith/constraint.h"
-
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-
-PureUpdateSimplexDecisionProcedure::PureUpdateSimplexDecisionProcedure(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc)
- : SimplexDecisionProcedure(linEq, errors, conflictChannel, tvmalloc)
-{ }
-
-Result::Sat PureUpdateSimplexDecisionProcedure::findModel(bool exactResult){
- Assert(d_conflictVariables.empty());
-
- static CVC4_THREADLOCAL(unsigned int) instance = 0;
- instance = instance + 1;
-
- if(d_errorSet.errorEmpty() && !d_errorSet.moreSignals()){
- Debug("arith::findModel") << "puFindModel("<< instance <<") "
- << "trivial" << endl;
- return Result::SAT;
- }
-
- // We need to reduce this because of
- d_errorSet.reduceToSignals();
- d_errorSet.setSelectionRule(VAR_ORDER);
-
- if(processSignals()){
- d_conflictVariables.purge();
-
- Debug("arith::findModel") << "puFindModel("<< instance <<") "
- << "early conflict" << endl;
- return Result::UNSAT;
- }else if(d_errorSet.errorEmpty()){
- Debug("arith::findModel") << "puFindModel("<< instance <<") "
- << "fixed itself" << endl;
- Assert(!d_errorSet.moreSignals());
- return Result::SAT;
- }
-
- Debug("arith::findModel") << "puFindModel(" << instance <<") "
- << "start non-trivial" << endl;
-
- static const bool verbose = false;
- Result::Sat result = Result::SAT_UNKNOWN;
-
- if(result == Result::SAT_UNKNOWN){
- if(attemptPureUpdates()){
- result = Result::UNSAT;
- }
- if(result == Result::UNSAT){
- ++(d_statistics.d_pureUpdateFoundUnsat);
- if(verbose){ Message() << "pure updates found unsat" << endl; }
- }else if(d_errorSet.errorEmpty()){
- ++(d_statistics.d_pureUpdateFoundSat);
- if(verbose){ Message() << "pure updates found model" << endl; }
- }else{
- ++(d_statistics.d_pureUpdateMissed);
- if(verbose){ Message() << "pure updates missed" << endl; }
- }
- }
-
- Assert(!d_errorSet.moreSignals());
- if(result == Result::SAT_UNKNOWN && d_errorSet.errorEmpty()){
- result = Result::SAT;
- }
-
- // ensure that the conflict variable is still in the queue.
- d_conflictVariables.purge();
-
- Assert(d_focusErrorVar == ARITHVAR_SENTINEL);
- Debug("arith::findModel") << "end findModel() " << instance << " "
- << result << endl;
-
- return result;
-}
-
-
-
-PureUpdateSimplexDecisionProcedure::Statistics::Statistics():
- d_pureUpdateFoundUnsat("theory::arith::PureUpdate::FoundUnsat", 0),
- d_pureUpdateFoundSat("theory::arith::PureUpdate::FoundSat", 0),
- d_pureUpdateMissed("theory::arith::PureUpdate::Missed", 0),
- d_pureUpdates("theory::arith::PureUpdate::updates", 0),
- d_pureUpdateDropped("theory::arith::PureUpdate::dropped", 0),
- d_pureUpdateConflicts("theory::arith::PureUpdate::conflicts", 0),
- d_foundConflicts("theory::arith::PureUpdate::foundConflicts", 0),
- d_attemptPureUpdatesTimer("theory::arith::PureUpdate::timer"),
- d_processSignalsTime("theory::arith::PureUpdate::process::timer"),
- d_constructionTimer("theory::arith::PureUpdate::construction::timer")
-{
- StatisticsRegistry::registerStat(&d_pureUpdateFoundUnsat);
- StatisticsRegistry::registerStat(&d_pureUpdateFoundSat);
- StatisticsRegistry::registerStat(&d_pureUpdateMissed);
- StatisticsRegistry::registerStat(&d_pureUpdates);
- StatisticsRegistry::registerStat(&d_pureUpdateDropped);
- StatisticsRegistry::registerStat(&d_pureUpdateConflicts);
-
- StatisticsRegistry::registerStat(&d_foundConflicts);
-
- StatisticsRegistry::registerStat(&d_attemptPureUpdatesTimer);
- StatisticsRegistry::registerStat(&d_processSignalsTime);
- StatisticsRegistry::registerStat(&d_constructionTimer);
-}
-
-PureUpdateSimplexDecisionProcedure::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_pureUpdateFoundUnsat);
- StatisticsRegistry::unregisterStat(&d_pureUpdateFoundSat);
- StatisticsRegistry::unregisterStat(&d_pureUpdateMissed);
- StatisticsRegistry::unregisterStat(&d_pureUpdates);
- StatisticsRegistry::unregisterStat(&d_pureUpdateDropped);
- StatisticsRegistry::unregisterStat(&d_pureUpdateConflicts);
-
- StatisticsRegistry::unregisterStat(&d_foundConflicts);
-
- StatisticsRegistry::unregisterStat(&d_attemptPureUpdatesTimer);
- StatisticsRegistry::unregisterStat(&d_processSignalsTime);
- StatisticsRegistry::unregisterStat(&d_constructionTimer);
-}
-
-bool PureUpdateSimplexDecisionProcedure::attemptPureUpdates(){
- TimerStat::CodeTimer codeTimer(d_statistics.d_attemptPureUpdatesTimer);
-
- Assert(!d_errorSet.focusEmpty());
- Assert(d_errorSet.noSignals());
-
- d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_constructionTimer);
-
- UpdateInfo proposal;
- int boundImprovements = 0;
- int dropped = 0;
- int computations = 0;
-
- for( Tableau::RowIterator ri = d_tableau.basicRowIterator(d_focusErrorVar); !ri.atEnd(); ++ri){
- const Tableau::Entry& e = *ri;
-
- ArithVar curr = e.getColVar();
- if(curr == d_focusErrorVar){ continue; }
-
- int dir = e.getCoefficient().sgn();
- Assert(dir != 0);
-
- bool worthwhile = false;
-
- if( (dir > 0 && d_variables.cmpAssignmentUpperBound(curr) < 0) ||
- (dir < 0 && d_variables.cmpAssignmentLowerBound(curr) > 0) ){
-
- ++computations;
- proposal = UpdateInfo(curr, dir);
- d_linEq.computeSafeUpdate(proposal, &LinearEqualityModule::noPreference);
-
- Assert(proposal.errorsChange() <= 0);
- Assert(proposal.focusDirection() >= 0);
-
- worthwhile = proposal.errorsChange() < 0 ||
- (proposal.focusDirection() > 0 &&
- d_variables.boundCounts(curr).isZero() &&
- !proposal.describesPivot());
-
- Debug("pu::refined")
- << "pure update proposal "
- << curr << " "
- << worthwhile << " "
- << proposal
- << endl;
- }
- if(worthwhile){
- Debug("pu") << d_variables.getAssignment(d_focusErrorVar) << endl;
-
- BoundCounts before = d_variables.boundCounts(curr);
- DeltaRational newAssignment =
- d_variables.getAssignment(curr) + proposal.nonbasicDelta();
- d_linEq.updateTracked(curr, newAssignment);
- BoundCounts after = d_variables.boundCounts(curr);
-
- ++d_statistics.d_pureUpdates;
- ++boundImprovements;
- Debug("pu") << boundImprovements << ": " << curr
- << " before: " << before
- << " after: " << after
- << e.getCoefficient()
- << d_variables.getAssignment(d_focusErrorVar) << endl;
-
- uint32_t prevSize = d_errorSet.errorSize();
- Assert(d_errorSet.moreSignals());
- if(Debug.isOn("pu")){ d_errorSet.debugPrint(Debug("pu")); }
- while(d_errorSet.moreSignals()){
- ArithVar updated = d_errorSet.topSignal();
- bool wasInError = d_errorSet.inError(updated);
- d_errorSet.popSignal();
- if(updated == curr){ continue; }
- Assert(d_tableau.isBasic(updated));
- if(!d_linEq.basicIsTracked(updated)){continue;}
-
-
- Assert(d_linEq.basicIsTracked(updated));
- Assert(wasInError || d_variables.assignmentIsConsistent(updated));
-
- if(!d_variables.assignmentIsConsistent(updated)
- && checkBasicForConflict(updated)){
- Assert(!d_conflictVariables.isMember(updated) );
- Debug("pu")
- << "It worked? "
- << d_statistics.d_pureUpdateConflicts.getData()
- << " " << curr
- << " " << checkBasicForConflict(updated) << endl;
- reportConflict(updated);
- ++(d_statistics.d_foundConflicts);
- ++(d_statistics.d_pureUpdateConflicts);
- }
- }
- if(d_conflictVariables.empty()){
- if(Debug.isOn("pu")){ d_errorSet.debugPrint(Debug("pu")); }
- uint32_t currSize = d_errorSet.errorSize();
- Assert(currSize <= prevSize);
- if(currSize < prevSize){
- dropped+= prevSize - currSize;
- if(currSize == 0){
- break;
- }
- }
- }else{
- break;
- }
- }
- }
-
- tearDownInfeasiblityFunction(d_statistics.d_constructionTimer, d_focusErrorVar);
- d_focusErrorVar = ARITHVAR_SENTINEL;
-
- (d_statistics.d_pureUpdateDropped) += dropped;
-
- Assert(d_errorSet.noSignals());
- return !d_conflictVariables.empty();
-}
-
-
-}/* CVC4::theory::arith namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/arith/simplex-converge.cpp b/src/theory/arith/simplex-converge.cpp
deleted file mode 100644
index decce3882..000000000
--- a/src/theory/arith/simplex-converge.cpp
+++ /dev/null
@@ -1,1674 +0,0 @@
-/********************* */
-/*! \file simplex.cpp
- ** \verbatim
- ** Original author: taking
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** 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/arith/simplex.h"
-#include "theory/arith/options.h"
-
-using namespace std;
-
-using namespace CVC4;
-using namespace CVC4::kind;
-
-using namespace CVC4::theory;
-using namespace CVC4::theory::arith;
-
-static const bool CHECK_AFTER_PIVOT = true;
-
-SimplexDecisionProcedure::SimplexDecisionProcedure(LinearEqualityModule& linEq, NodeCallBack& conflictChannel, ArithVarMalloc& malloc, ConstraintDatabase& cd) :
- d_conflictVariable(ARITHVAR_SENTINEL),
- d_linEq(linEq),
- d_partialModel(d_linEq.getPartialModel()),
- d_tableau(d_linEq.getTableau()),
- d_queue(d_partialModel, d_tableau),
- d_numVariables(0),
- d_conflictChannel(conflictChannel),
- d_pivotsInRound(),
- d_DELTA_ZERO(0,0),
- d_arithVarMalloc(malloc),
- d_constraintDatabase(cd),
- d_optRow(ARITHVAR_SENTINEL),
- d_negOptConstant(d_DELTA_ZERO)
-{
- switch(ArithHeuristicPivotRule rule = options::arithHeuristicPivotRule()) {
- case MINIMUM:
- d_queue.setPivotRule(ArithPriorityQueue::MINIMUM);
- break;
- case BREAK_TIES:
- d_queue.setPivotRule(ArithPriorityQueue::BREAK_TIES);
- break;
- case MAXIMUM:
- d_queue.setPivotRule(ArithPriorityQueue::MAXIMUM);
- break;
- default:
- Unhandled(rule);
- }
-
- srand(62047);
-}
-
-SimplexDecisionProcedure::Statistics::Statistics():
- d_statUpdateConflicts("theory::arith::UpdateConflicts", 0),
- d_findConflictOnTheQueueTime("theory::arith::findConflictOnTheQueueTime"),
- d_attemptBeforeDiffSearch("theory::arith::qi::BeforeDiffSearch::attempt",0),
- d_successBeforeDiffSearch("theory::arith::qi::BeforeDiffSearch::success",0),
- d_attemptAfterDiffSearch("theory::arith::qi::AfterDiffSearch::attempt",0),
- d_successAfterDiffSearch("theory::arith::qi::AfterDiffSearch::success",0),
- d_attemptDuringDiffSearch("theory::arith::qi::DuringDiffSearch::attempt",0),
- d_successDuringDiffSearch("theory::arith::qi::DuringDiffSearch::success",0),
- d_attemptDuringVarOrderSearch("theory::arith::qi::DuringVarOrderSearch::attempt",0),
- d_successDuringVarOrderSearch("theory::arith::qi::DuringVarOrderSearch::success",0),
- d_attemptAfterVarOrderSearch("theory::arith::qi::AfterVarOrderSearch::attempt",0),
- d_successAfterVarOrderSearch("theory::arith::qi::AfterVarOrderSearch::success",0),
- d_weakeningAttempts("theory::arith::weakening::attempts",0),
- d_weakeningSuccesses("theory::arith::weakening::success",0),
- d_weakenings("theory::arith::weakening::total",0),
- d_weakenTime("theory::arith::weakening::time"),
- d_simplexConflicts("theory::arith::simplexConflicts",0),
- // primal
- d_primalTimer("theory::arith::primal::overall::timer"),
- d_internalTimer("theory::arith::primal::internal::timer"),
- d_primalCalls("theory::arith::primal::calls",0),
- d_primalSatCalls("theory::arith::primal::calls::sat",0),
- d_primalUnsatCalls("theory::arith::primal::calls::unsat",0),
- d_primalPivots("theory::arith::primal::pivots",0),
- d_primalImprovingPivots("theory::arith::primal::pivots::improving",0),
- d_primalThresholdReachedPivot("theory::arith::primal::thresholds",0),
- d_primalThresholdReachedPivot_dropped("theory::arith::primal::thresholds::dropped",0),
- d_primalReachedMaxPivots("theory::arith::primal::maxpivots",0),
- d_primalReachedMaxPivots_contractMadeProgress("theory::arith::primal::maxpivots::contract",0),
- d_primalReachedMaxPivots_checkForConflictWorked("theory::arith::primal::maxpivots::checkworked",0),
- d_primalGlobalMinimum("theory::arith::primal::minimum",0),
- d_primalGlobalMinimum_rowConflictWorked("theory::arith::primal::minimum::checkworked",0),
- d_primalGlobalMinimum_firstHalfWasSat("theory::arith::primal::minimum::firsthalf::sat",0),
- d_primalGlobalMinimum_firstHalfWasUnsat("theory::arith::primal::minimum::firsthalf::unsat",0),
- d_primalGlobalMinimum_contractMadeProgress("theory::arith::primal::minimum::progress",0),
- d_unboundedFound("theory::arith::primal::unbounded",0),
- d_unboundedFound_drive("theory::arith::primal::unbounded::drive",0),
- d_unboundedFound_dropped("theory::arith::primal::unbounded::dropped",0)
-{
- StatisticsRegistry::registerStat(&d_statUpdateConflicts);
-
- StatisticsRegistry::registerStat(&d_findConflictOnTheQueueTime);
-
- StatisticsRegistry::registerStat(&d_attemptBeforeDiffSearch);
- StatisticsRegistry::registerStat(&d_successBeforeDiffSearch);
- StatisticsRegistry::registerStat(&d_attemptAfterDiffSearch);
- StatisticsRegistry::registerStat(&d_successAfterDiffSearch);
- StatisticsRegistry::registerStat(&d_attemptDuringDiffSearch);
- StatisticsRegistry::registerStat(&d_successDuringDiffSearch);
- StatisticsRegistry::registerStat(&d_attemptDuringVarOrderSearch);
- StatisticsRegistry::registerStat(&d_successDuringVarOrderSearch);
- StatisticsRegistry::registerStat(&d_attemptAfterVarOrderSearch);
- StatisticsRegistry::registerStat(&d_successAfterVarOrderSearch);
-
- StatisticsRegistry::registerStat(&d_weakeningAttempts);
- StatisticsRegistry::registerStat(&d_weakeningSuccesses);
- StatisticsRegistry::registerStat(&d_weakenings);
- StatisticsRegistry::registerStat(&d_weakenTime);
-
- StatisticsRegistry::registerStat(&d_simplexConflicts);
-
- //primal
- StatisticsRegistry::registerStat(&d_primalTimer);
- StatisticsRegistry::registerStat(&d_internalTimer);
-
- StatisticsRegistry::registerStat(&d_primalCalls);
- StatisticsRegistry::registerStat(&d_primalSatCalls);
- StatisticsRegistry::registerStat(&d_primalUnsatCalls);
-
- StatisticsRegistry::registerStat(&d_primalPivots);
- StatisticsRegistry::registerStat(&d_primalImprovingPivots);
-
- StatisticsRegistry::registerStat(&d_primalThresholdReachedPivot);
- StatisticsRegistry::registerStat(&d_primalThresholdReachedPivot_dropped);
-
- StatisticsRegistry::registerStat(&d_primalReachedMaxPivots);
- StatisticsRegistry::registerStat(&d_primalReachedMaxPivots_contractMadeProgress);
- StatisticsRegistry::registerStat(&d_primalReachedMaxPivots_checkForConflictWorked);
-
-
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_rowConflictWorked);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_firstHalfWasSat);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_firstHalfWasUnsat);
- StatisticsRegistry::registerStat(&d_primalGlobalMinimum_contractMadeProgress);
-
-
- StatisticsRegistry::registerStat(&d_unboundedFound);
- StatisticsRegistry::registerStat(&d_unboundedFound_drive);
- StatisticsRegistry::registerStat(&d_unboundedFound_dropped);
-
-}
-
-SimplexDecisionProcedure::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_statUpdateConflicts);
-
- StatisticsRegistry::unregisterStat(&d_findConflictOnTheQueueTime);
-
- StatisticsRegistry::unregisterStat(&d_attemptBeforeDiffSearch);
- StatisticsRegistry::unregisterStat(&d_successBeforeDiffSearch);
- StatisticsRegistry::unregisterStat(&d_attemptAfterDiffSearch);
- StatisticsRegistry::unregisterStat(&d_successAfterDiffSearch);
- StatisticsRegistry::unregisterStat(&d_attemptDuringDiffSearch);
- StatisticsRegistry::unregisterStat(&d_successDuringDiffSearch);
- StatisticsRegistry::unregisterStat(&d_attemptDuringVarOrderSearch);
- StatisticsRegistry::unregisterStat(&d_successDuringVarOrderSearch);
- StatisticsRegistry::unregisterStat(&d_attemptAfterVarOrderSearch);
- StatisticsRegistry::unregisterStat(&d_successAfterVarOrderSearch);
-
- StatisticsRegistry::unregisterStat(&d_weakeningAttempts);
- StatisticsRegistry::unregisterStat(&d_weakeningSuccesses);
- StatisticsRegistry::unregisterStat(&d_weakenings);
- StatisticsRegistry::unregisterStat(&d_weakenTime);
-
- StatisticsRegistry::unregisterStat(&d_simplexConflicts);
-
- //primal
- StatisticsRegistry::unregisterStat(&d_primalTimer);
- StatisticsRegistry::unregisterStat(&d_internalTimer);
-
- StatisticsRegistry::unregisterStat(&d_primalCalls);
- StatisticsRegistry::unregisterStat(&d_primalSatCalls);
- StatisticsRegistry::unregisterStat(&d_primalUnsatCalls);
-
- StatisticsRegistry::unregisterStat(&d_primalPivots);
- StatisticsRegistry::unregisterStat(&d_primalImprovingPivots);
-
- StatisticsRegistry::unregisterStat(&d_primalThresholdReachedPivot);
- StatisticsRegistry::unregisterStat(&d_primalThresholdReachedPivot_dropped);
-
- StatisticsRegistry::unregisterStat(&d_primalReachedMaxPivots);
- StatisticsRegistry::unregisterStat(&d_primalReachedMaxPivots_contractMadeProgress);
- StatisticsRegistry::unregisterStat(&d_primalReachedMaxPivots_checkForConflictWorked);
-
-
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_rowConflictWorked);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_firstHalfWasSat);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_firstHalfWasUnsat);
- StatisticsRegistry::unregisterStat(&d_primalGlobalMinimum_contractMadeProgress);
-
- StatisticsRegistry::unregisterStat(&d_unboundedFound);
- StatisticsRegistry::unregisterStat(&d_unboundedFound_drive);
- StatisticsRegistry::unregisterStat(&d_unboundedFound_dropped);
-}
-
-
-
-
-ArithVar SimplexDecisionProcedure::minVarOrder(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- // Assert(!simp.d_tableau.isBasic(x));
- // Assert(!simp.d_tableau.isBasic(y));
- if(x <= y){
- return x;
- } else {
- return y;
- }
-}
-
-ArithVar SimplexDecisionProcedure::minColLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- Assert(!simp.d_tableau.isBasic(x));
- Assert(!simp.d_tableau.isBasic(y));
- uint32_t xLen = simp.d_tableau.getColLength(x);
- uint32_t yLen = simp.d_tableau.getColLength(y);
- if( xLen > yLen){
- return y;
- } else if( xLen== yLen ){
- return minVarOrder(simp,x,y);
- }else{
- return x;
- }
-}
-
-ArithVar SimplexDecisionProcedure::minRowLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- Assert(simp.d_tableau.isBasic(x));
- Assert(simp.d_tableau.isBasic(y));
- uint32_t xLen = simp.d_tableau.getRowLength(simp.d_tableau.basicToRowIndex(x));
- uint32_t yLen = simp.d_tableau.getRowLength(simp.d_tableau.basicToRowIndex(y));
- if( xLen > yLen){
- return y;
- } else if( xLen == yLen ){
- return minVarOrder(simp,x,y);
- }else{
- return x;
- }
-}
-ArithVar SimplexDecisionProcedure::minBoundAndRowCount(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y){
- Assert(x != ARITHVAR_SENTINEL);
- Assert(y != ARITHVAR_SENTINEL);
- Assert(!simp.d_tableau.isBasic(x));
- Assert(!simp.d_tableau.isBasic(y));
- if(simp.d_partialModel.hasEitherBound(x) && !simp.d_partialModel.hasEitherBound(y)){
- return y;
- }else if(!simp.d_partialModel.hasEitherBound(x) && simp.d_partialModel.hasEitherBound(y)){
- return x;
- }else {
- return minColLength(simp, x, y);
- }
-}
-
-template <bool above>
-ArithVar SimplexDecisionProcedure::selectSlack(ArithVar x_i, SimplexDecisionProcedure::PreferenceFunction pref){
- ArithVar slack = ARITHVAR_SENTINEL;
-
- for(Tableau::RowIterator iter = d_tableau.basicRowIterator(x_i); !iter.atEnd(); ++iter){
- const Tableau::Entry& entry = *iter;
- ArithVar nonbasic = entry.getColVar();
- if(nonbasic == x_i) continue;
-
- const Rational& a_ij = entry.getCoefficient();
- int sgn = a_ij.sgn();
- if(isAcceptableSlack<above>(sgn, nonbasic)){
- //If one of the above conditions is met, we have found an acceptable
- //nonbasic variable to pivot x_i with. We can now choose which one we
- //prefer the most.
- slack = (slack == ARITHVAR_SENTINEL) ? nonbasic : pref(*this, slack, nonbasic);
- }
- }
-
- return slack;
-}
-
-Node betterConflict(TNode x, TNode y){
- if(x.isNull()) return y;
- else if(y.isNull()) return x;
- else if(x.getNumChildren() <= y.getNumChildren()) return x;
- else return y;
-}
-
-bool SimplexDecisionProcedure::findConflictOnTheQueue(SearchPeriod type) {
- TimerStat::CodeTimer codeTimer(d_statistics.d_findConflictOnTheQueueTime);
- Assert(d_successes.empty());
-
- switch(type){
- case BeforeDiffSearch: ++(d_statistics.d_attemptBeforeDiffSearch); break;
- case DuringDiffSearch: ++(d_statistics.d_attemptDuringDiffSearch); break;
- case AfterDiffSearch: ++(d_statistics.d_attemptAfterDiffSearch); break;
- case DuringVarOrderSearch: ++(d_statistics.d_attemptDuringVarOrderSearch); break;
- case AfterVarOrderSearch: ++(d_statistics.d_attemptAfterVarOrderSearch); break;
- }
-
- ArithPriorityQueue::const_iterator i = d_queue.begin();
- ArithPriorityQueue::const_iterator end = d_queue.end();
- for(; i != end; ++i){
- ArithVar x_i = *i;
-
- if(x_i != d_conflictVariable && d_tableau.isBasic(x_i) && !d_successes.isMember(x_i)){
- Node possibleConflict = checkBasicForConflict(x_i);
- if(!possibleConflict.isNull()){
- d_successes.add(x_i);
- reportConflict(possibleConflict);
- }
- }
- }
- if(!d_successes.empty()){
- switch(type){
- case BeforeDiffSearch: ++(d_statistics.d_successBeforeDiffSearch); break;
- case DuringDiffSearch: ++(d_statistics.d_successDuringDiffSearch); break;
- case AfterDiffSearch: ++(d_statistics.d_successAfterDiffSearch); break;
- case DuringVarOrderSearch: ++(d_statistics.d_successDuringVarOrderSearch); break;
- case AfterVarOrderSearch: ++(d_statistics.d_successAfterVarOrderSearch); break;
- }
- d_successes.purge();
- return true;
- }else{
- return false;
- }
-}
-
-Result::Sat SimplexDecisionProcedure::dualFindModel(bool exactResult){
- Assert(d_conflictVariable == ARITHVAR_SENTINEL);
- Assert(d_queue.inCollectionMode());
-
- if(d_queue.empty()){
- return Result::SAT;
- }
- static CVC4_THREADLOCAL(unsigned int) instance = 0;
- instance = instance + 1;
- Debug("arith::findModel") << "begin findModel()" << instance << endl;
-
- d_queue.transitionToDifferenceMode();
-
- Result::Sat result = Result::SAT_UNKNOWN;
-
- if(d_queue.empty()){
- result = Result::SAT;
- }else if(d_queue.size() > 1){
- if(findConflictOnTheQueue(BeforeDiffSearch)){
- result = Result::UNSAT;
- }
- }
- static const bool verbose = false;
- exactResult |= options::arithStandardCheckVarOrderPivots() < 0;
- const uint32_t inexactResultsVarOrderPivots = exactResult ? 0 : options::arithStandardCheckVarOrderPivots();
-
- uint32_t checkPeriod = options::arithSimplexCheckPeriod();
- if(result == Result::SAT_UNKNOWN){
- uint32_t numDifferencePivots = options::arithHeuristicPivots() < 0 ?
- d_numVariables + 1 : options::arithHeuristicPivots();
- // The signed to unsigned conversion is safe.
- uint32_t pivotsRemaining = numDifferencePivots;
- while(!d_queue.empty() &&
- result != Result::UNSAT &&
- pivotsRemaining > 0){
- uint32_t pivotsToDo = min(checkPeriod, pivotsRemaining);
- pivotsRemaining -= pivotsToDo;
- if(searchForFeasibleSolution(pivotsToDo)){
- result = Result::UNSAT;
- }//Once every CHECK_PERIOD examine the entire queue for conflicts
- if(result != Result::UNSAT){
- if(findConflictOnTheQueue(DuringDiffSearch)) { result = Result::UNSAT; }
- }else{
- findConflictOnTheQueue(AfterDiffSearch); // already unsat
- }
- }
-
- if(verbose && numDifferencePivots > 0){
- if(result == Result::UNSAT){
- Message() << "diff order found unsat" << endl;
- }else if(d_queue.empty()){
- Message() << "diff order found model" << endl;
- }else{
- Message() << "diff order missed" << endl;
- }
- }
- }
-
- if(!d_queue.empty() && result != Result::UNSAT){
- if(exactResult){
- d_queue.transitionToVariableOrderMode();
-
- while(!d_queue.empty() && result != Result::UNSAT){
- if(searchForFeasibleSolution(checkPeriod)){
- result = Result::UNSAT;
- }
-
- //Once every CHECK_PERIOD examine the entire queue for conflicts
- if(result != Result::UNSAT){
- if(findConflictOnTheQueue(DuringVarOrderSearch)){
- result = Result::UNSAT;
- }
- } else{
- findConflictOnTheQueue(AfterVarOrderSearch);
- }
- }
- if(verbose){
- if(result == Result::UNSAT){
- Message() << "bland found unsat" << endl;
- }else if(d_queue.empty()){
- Message() << "bland found model" << endl;
- }else{
- Message() << "bland order missed" << endl;
- }
- }
- }else{
- d_queue.transitionToVariableOrderMode();
-
- if(searchForFeasibleSolution(inexactResultsVarOrderPivots)){
- result = Result::UNSAT;
- findConflictOnTheQueue(AfterVarOrderSearch); // already unsat
- }else{
- if(findConflictOnTheQueue(AfterVarOrderSearch)) { result = Result::UNSAT; }
- }
-
- if(verbose){
- if(result == Result::UNSAT){
- Message() << "restricted var order found unsat" << endl;
- }else if(d_queue.empty()){
- Message() << "restricted var order found model" << endl;
- }else{
- Message() << "restricted var order missed" << endl;
- }
- }
- }
- }
-
- if(result == Result::SAT_UNKNOWN && d_queue.empty()){
- result = Result::SAT;
- }
-
-
-
- d_pivotsInRound.purge();
- // ensure that the conflict variable is still in the queue.
- if(d_conflictVariable != ARITHVAR_SENTINEL){
- d_queue.enqueueIfInconsistent(d_conflictVariable);
- }
- d_conflictVariable = ARITHVAR_SENTINEL;
-
- d_queue.transitionToCollectionMode();
- Assert(d_queue.inCollectionMode());
- Debug("arith::findModel") << "end findModel() " << instance << " " << result << endl;
- return result;
-
-
- // Assert(foundConflict || d_queue.empty());
-
- // // Curiously the invariant that we always do a full check
- // // means that the assignment we can always empty these queues.
- // d_queue.clear();
- // d_pivotsInRound.purge();
- // d_conflictVariable = ARITHVAR_SENTINEL;
-
- // Assert(!d_queue.inCollectionMode());
- // d_queue.transitionToCollectionMode();
-
-
- // Assert(d_queue.inCollectionMode());
-
- // Debug("arith::findModel") << "end findModel() " << instance << endl;
-
- // return foundConflict;
-}
-
-
-
-Node SimplexDecisionProcedure::checkBasicForConflict(ArithVar basic){
-
- Assert(d_tableau.isBasic(basic));
- const DeltaRational& beta = d_partialModel.getAssignment(basic);
-
- if(d_partialModel.strictlyLessThanLowerBound(basic, beta)){
- ArithVar x_j = selectSlackUpperBound(basic);
- if(x_j == ARITHVAR_SENTINEL ){
- return generateConflictBelowLowerBound(basic);
- }
- }else if(d_partialModel.strictlyGreaterThanUpperBound(basic, beta)){
- ArithVar x_j = selectSlackLowerBound(basic);
- if(x_j == ARITHVAR_SENTINEL ){
- return generateConflictAboveUpperBound(basic);
- }
- }
- return Node::null();
-}
-
-//corresponds to Check() in dM06
-//template <SimplexDecisionProcedure::PreferenceFunction pf>
-bool SimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingIterations){
- Debug("arith") << "searchForFeasibleSolution" << endl;
- Assert(remainingIterations > 0);
-
- while(remainingIterations > 0){
- if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
-
- ArithVar x_i = d_queue.dequeueInconsistentBasicVariable();
- Debug("arith::update::select") << "selectSmallestInconsistentVar()=" << x_i << endl;
- if(x_i == ARITHVAR_SENTINEL){
- Debug("arith_update") << "No inconsistent variables" << endl;
- return false; //sat
- }
-
- --remainingIterations;
-
- bool useVarOrderPivot = d_pivotsInRound.count(x_i) >= options::arithPivotThreshold();
- if(!useVarOrderPivot){
- d_pivotsInRound.add(x_i);
- }
-
-
- Debug("playground") << "pivots in rounds: " << d_pivotsInRound.count(x_i)
- << " use " << useVarOrderPivot
- << " threshold " << options::arithPivotThreshold()
- << endl;
-
- PreferenceFunction pf = useVarOrderPivot ? minVarOrder : minBoundAndRowCount;
-
- DeltaRational beta_i = d_partialModel.getAssignment(x_i);
- ArithVar x_j = ARITHVAR_SENTINEL;
-
- if(d_partialModel.strictlyLessThanLowerBound(x_i, beta_i)){
- x_j = selectSlackUpperBound(x_i, pf);
- if(x_j == ARITHVAR_SENTINEL ){
- ++(d_statistics.d_statUpdateConflicts);
- Node conflict = generateConflictBelowLowerBound(x_i); //unsat
- d_conflictVariable = x_i;
- reportConflict(conflict);
- return true;
- }
- DeltaRational l_i = d_partialModel.getLowerBound(x_i);
- d_linEq.pivotAndUpdate(x_i, x_j, l_i);
-
- }else if(d_partialModel.strictlyGreaterThanUpperBound(x_i, beta_i)){
- x_j = selectSlackLowerBound(x_i, pf);
- if(x_j == ARITHVAR_SENTINEL ){
- ++(d_statistics.d_statUpdateConflicts);
- Node conflict = generateConflictAboveUpperBound(x_i); //unsat
-
- d_conflictVariable = x_i;
- reportConflict(conflict);
- return true;
- }
- DeltaRational u_i = d_partialModel.getUpperBound(x_i);
- d_linEq.pivotAndUpdate(x_i, x_j, u_i);
- }
- Assert(x_j != ARITHVAR_SENTINEL);
-
- //Check to see if we already have a conflict with x_j to prevent wasteful work
- if(CHECK_AFTER_PIVOT){
- Node possibleConflict = checkBasicForConflict(x_j);
- if(!possibleConflict.isNull()){
- d_conflictVariable = x_j;
- reportConflict(possibleConflict);
- return true; // unsat
- }
- }
- }
- Assert(remainingIterations == 0);
-
- return false;
-}
-
-
-
-Constraint SimplexDecisionProcedure::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic){
-
- int sgn = coeff.sgn();
- bool ub = aboveUpper?(sgn < 0) : (sgn > 0);
-
- Constraint c = ub ?
- d_partialModel.getUpperBoundConstraint(v) :
- d_partialModel.getLowerBoundConstraint(v);
-
-// #warning "revisit"
-// Node exp = ub ?
-// d_partialModel.explainUpperBound(v) :
-// d_partialModel.explainLowerBound(v);
-
- bool weakened;
- do{
- const DeltaRational& bound = c->getValue();
-
- weakened = false;
-
- Constraint weaker = ub?
- c->getStrictlyWeakerUpperBound(true, true):
- c->getStrictlyWeakerLowerBound(true, true);
-
- // Node weaker = ub?
- // d_propManager.strictlyWeakerAssertedUpperBound(v, bound):
- // d_propManager.strictlyWeakerAssertedLowerBound(v, bound);
-
- if(weaker != NullConstraint){
- //if(!weaker.isNull()){
- const DeltaRational& weakerBound = weaker->getValue();
- //DeltaRational weakerBound = asDeltaRational(weaker);
-
- DeltaRational diff = aboveUpper ? bound - weakerBound : weakerBound - bound;
- //if var == basic,
- // if aboveUpper, weakerBound > bound, multiply by -1
- // if !aboveUpper, weakerBound < bound, multiply by -1
- diff = diff * coeff;
- if(surplus > diff){
- ++d_statistics.d_weakenings;
- weakened = true;
- anyWeakening = true;
- surplus = surplus - diff;
-
- Debug("weak") << "found:" << endl;
- if(v == basic){
- Debug("weak") << " basic: ";
- }
- Debug("weak") << " " << surplus << " "<< diff << endl
- << " " << bound << c << endl
- << " " << weakerBound << weaker << endl;
-
- Assert(diff > d_DELTA_ZERO);
- c = weaker;
- }
- }
- }while(weakened);
-
- return c;
-}
-
-Node SimplexDecisionProcedure::weakenConflict(bool aboveUpper, ArithVar basicVar){
- TimerStat::CodeTimer codeTimer(d_statistics.d_weakenTime);
-
- const DeltaRational& assignment = d_partialModel.getAssignment(basicVar);
- DeltaRational surplus;
- if(aboveUpper){
- Assert(d_partialModel.hasUpperBound(basicVar));
- Assert(assignment > d_partialModel.getUpperBound(basicVar));
- surplus = assignment - d_partialModel.getUpperBound(basicVar);
- }else{
- Assert(d_partialModel.hasLowerBound(basicVar));
- Assert(assignment < d_partialModel.getLowerBound(basicVar));
- surplus = d_partialModel.getLowerBound(basicVar) - assignment;
- }
-
- NodeBuilder<> conflict(kind::AND);
- bool anyWeakenings = false;
- for(Tableau::RowIterator i = d_tableau.basicRowIterator(basicVar); !i.atEnd(); ++i){
- const Tableau::Entry& entry = *i;
- ArithVar v = entry.getColVar();
- const Rational& coeff = entry.getCoefficient();
- bool weakening = false;
- Constraint c = weakestExplanation(aboveUpper, surplus, v, coeff, weakening, basicVar);
- Debug("weak") << "weak : " << weakening << " "
- << c->assertedToTheTheory() << " "
- << d_partialModel.getAssignment(v) << " "
- << c << endl
- << c->explainForConflict() << endl;
- anyWeakenings = anyWeakenings || weakening;
-
- Debug("weak") << "weak : " << c->explainForConflict() << endl;
- c->explainForConflict(conflict);
- }
- ++d_statistics.d_weakeningAttempts;
- if(anyWeakenings){
- ++d_statistics.d_weakeningSuccesses;
- }
- return conflict;
-}
-
-
-Node SimplexDecisionProcedure::generateConflictAboveUpperBound(ArithVar conflictVar){
- return weakenConflict(true, conflictVar);
-}
-
-Node SimplexDecisionProcedure::generateConflictBelowLowerBound(ArithVar conflictVar){
- return weakenConflict(false, conflictVar);
-}
-
-
-// responses
-// unbounded below(arithvar)
-// reached threshold
-// reached maxpivots
-// reached GlobalMinimumd
-//
-SimplexDecisionProcedure::PrimalResponse SimplexDecisionProcedure::primal(uint32_t maxIterations)
-{
- Assert(d_optRow != ARITHVAR_SENTINEL);
-
- for(uint32_t iteration = 0; iteration < maxIterations; iteration++){
- if(belowThreshold()){
- return ReachedThresholdValue;
- }
-
- PrimalResponse res = primalCheck();
- switch(res){
- case GlobalMinimum:
- case FoundUnboundedVariable:
- return res;
- case NoProgressOnLeaving:
- ++d_statistics.d_primalPivots;
- ++d_pivotsSinceOptProgress;
- ++d_pivotsSinceLastCheck;
- ++d_pivotsSinceErrorProgress;
-
- d_linEq.pivotAndUpdate(d_primalCarry.d_entering, d_primalCarry.d_leaving, d_partialModel.getAssignment(d_primalCarry.d_entering));
-
- if(Debug.isOn("primal::tableau")){
- d_linEq.debugCheckTableau();
- }
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("MakeProgressOnLeaving")); }
-
- break;
- case MakeProgressOnLeaving:
- {
- ++d_statistics.d_primalPivots;
- ++d_statistics.d_primalImprovingPivots;
-
- d_pivotsSinceOptProgress = 0;
- ++d_pivotsSinceErrorProgress;
- ++d_pivotsSinceLastCheck;
-
- d_linEq.pivotAndUpdate(d_primalCarry.d_entering, d_primalCarry.d_leaving, d_primalCarry.d_nextEnteringValue);
-
- static int helpful = 0;
- static int hurtful = 0;
- static int penguin = 0;
- if(d_currentErrorVariables.isKey(d_primalCarry.d_entering)){
- cout << "entering is error " << d_primalCarry.d_entering;
- if(d_currentErrorVariables[d_primalCarry.d_entering].errorIsLeqZero(d_partialModel)){
- cout << " now below threshold (" << (++helpful) << ") " << d_pivotsSinceErrorProgress << endl;
- }else{
- cout << "ouch (" << (++hurtful) << ")"<< d_pivotsSinceErrorProgress << endl;
- }
- }else if(d_currentErrorVariables.isKey(d_primalCarry.d_leaving)){
- cout << "leaving is error " << d_primalCarry.d_leaving;
- if(d_currentErrorVariables[d_primalCarry.d_leaving].errorIsLeqZero(d_partialModel)){
- cout << " now below threshold(" << (++helpful) << ")" << d_pivotsSinceErrorProgress << endl;
- }else{
- cout << "ouch (" << (++hurtful) << ")" << d_pivotsSinceErrorProgress<< endl;
- }
- }else{
- cout << " penguin (" << (++penguin) << ")" << d_pivotsSinceErrorProgress<< endl;
- }
-
- if(Debug.isOn("primal::tableau")){
- d_linEq.debugCheckTableau();
- }
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("MakeProgressOnLeaving")); }
- }
- break;
- default:
- Unreachable();
- }
- }
- return UsedMaxPivots;
-}
-
-
-/**
- * Error set
- * ErrorVariable |-> {ErrorVariable, InputVariable, InputConstraint}
- */
-
-/**
- * Returns SAT if it was able to satisfy all of the constraints in the error set
- * Returns UNSAT if it was able to able to find an error
- */
-Result::Sat SimplexDecisionProcedure::primalConverge(int depth){
- d_pivotsSinceLastCheck = 0;
-
- while(!d_currentErrorVariables.empty()){
- PrimalResponse res = primal(MAX_ITERATIONS - d_pivotsSinceLastCheck);
-
- switch(res){
- case FoundUnboundedVariable:
-
- // Drive the variable to at least 0
- // TODO This variable should be driven to a value that makes all of the error functions including it 0
- // It'll or another unbounded will be selected in the next round anyways so ignore for now.
- ++d_statistics.d_unboundedFound;
- if( !belowThreshold() ){
- driveOptToZero(d_primalCarry.d_unbounded);
- d_linEq.debugCheckTableau();
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("primalConverge")); }
-
- ++d_statistics.d_unboundedFound_drive;
- }
- Assert(belowThreshold());
- {
- uint32_t dropped = contractErrorVariables(true);
- Debug("primal::converge") << "primalConverge -> FoundUnboundedVariable -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- d_statistics.d_unboundedFound_dropped += dropped;
- }
- break;
- case ReachedThresholdValue:
- ++d_statistics.d_primalThresholdReachedPivot;
-
- Assert(belowThreshold());
- {
- uint32_t dropped = contractErrorVariables(true);
- Debug("primal::converge") << "primalConverge -> ReachedThresholdValue -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- d_statistics.d_primalThresholdReachedPivot_dropped += dropped;
- }
- break;
- case UsedMaxPivots:
- {
- d_pivotsSinceLastCheck = 0;
- ++d_statistics.d_primalReachedMaxPivots;
-
- // periodically attempt to do the following :
- // contract the error variable
- // check for a conflict on an error variable
- uint32_t dropped = contractErrorVariables(false);
-
- if( checkForRowConflicts() ){ // try to periodically look for a row
- Debug("primal::converge") << "primalConverge -> UsedMaxPivots -> unsat " << endl;
-
- ++d_statistics.d_primalReachedMaxPivots_checkForConflictWorked;
- return Result::UNSAT; // row conflicts are minimal so stop.
- }
-
- if(dropped > 0){
- Debug("primal::converge") << "primalConverge -> UsedMaxPivots -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- ++d_statistics.d_primalReachedMaxPivots_contractMadeProgress;
- }else{
- Debug("primal::converge") << "primalConverge -> UsedMaxPivots -> nothing " << endl;
- }
- }
- break;
- case GlobalMinimum:
- ++d_statistics.d_primalGlobalMinimum;
-
- // If the minimum is positive, this is unsat.
- // However, the optimization row is not necessarily a minimal conflict
- if(!belowThreshold()){
-
- if(d_currentErrorVariables.size() == 1){
- // The optimization function is exactly the same as the last remaining variable
- // The conflict for the row is the same as the conflict for the optimization function.
- bool foundConflict = checkForRowConflicts();
- Assert(foundConflict);
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> one variable" << endl;
-
- return Result::UNSAT;
- }else{
- // There are at least 2 error variables.
- // Look for a minimal conflict
-
-
- if(checkForRowConflicts() ){
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> postitive -> rowconflict " << endl;
-
- ++d_statistics.d_primalGlobalMinimum_rowConflictWorked;
- return Result::UNSAT;
- }
-
- uint32_t dropped = contractErrorVariables(false);
-
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> postitive -> dropped " << dropped << " to " << d_currentErrorVariables.size() << endl;
- if(dropped > 0){
- ++d_statistics.d_primalGlobalMinimum_contractMadeProgress;
- }
-
- ErrorMap half;
- d_currentErrorVariables.splitInto(half);
-
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> recursion " << depth << endl;
-
-
- reconstructOptimizationFunction();
- Result::Sat resultOnRemaining = primalConverge(depth + 1);
-
- if(resultOnRemaining == Result::UNSAT){
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> recursion " << depth << " was unsat " << endl;
- ++d_statistics.d_primalGlobalMinimum_firstHalfWasUnsat;
- restoreErrorVariables(half);
- return Result::UNSAT;
- }else{
- ++d_statistics.d_primalGlobalMinimum_firstHalfWasSat;
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> recursion " << depth << " was sat " << endl;
-
- Assert(resultOnRemaining == Result::SAT);
- Assert(d_currentErrorVariables.empty());
- d_currentErrorVariables.addAll(half);
- reconstructOptimizationFunction();
- return primalConverge(depth + 1);
- }
- }
-
- }else{
-
- // if the optimum is <= 0
- // drop all of the satisfied variables and continue;
- uint32_t dropped = contractErrorVariables(true);
- Debug("primal::converge") << "primalConverge -> GlobalMinimum -> negative -> dropped "<< dropped << " to " << d_currentErrorVariables.size() << endl;
-
- ++d_statistics.d_primalGlobalMinimum_contractMadeProgress;
- }
- break;
- default:
- Unreachable();
- }
- }
-
- return Result::SAT;
-}
-
-
-Result::Sat SimplexDecisionProcedure::primalFindModel(){
- Assert(d_primalCarry.isClear());
-
- // Reduce the queue to only contain violations
- reduceQueue();
-
- if(d_queue.empty()){
- return Result::SAT;
- }
- TimerStat::CodeTimer codeTimer(d_statistics.d_primalTimer);
-
- ++d_statistics.d_primalCalls;
-
- Debug("primalFindModel") << "primalFindModel() begin" << endl;
-
- const int PAUSE_RATE = 100;
- if(Debug.isOn("primal::pause") && d_statistics.d_primalCalls.getData() % PAUSE_RATE == 0){
- Debug("primal::pause") << "waiting for input: ";
- std::string dummy;
- std::getline(std::cin, dummy);
- }
-
- // TODO restore the tableau by ejecting variables
- // Tableau copy(d_tableau);
-
- Result::Sat answer;
- {
- TimerStat::CodeTimer codeTimer(d_statistics.d_internalTimer);
-
- // This is needed because of the fiddling with the partial model
- //context::Context::ScopedPush speculativePush(satContext);
-
- constructErrorVariables();
- constructOptimizationFunction();
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
- if(Debug.isOn("primal::consistent")){ d_linEq.debugEntireLinEqIsConsistent("primalFindModel 1"); }
- answer = primalConverge(0);
- }
- removeOptimizationFunction();
-
-
- // exit
- uint32_t nc = d_tableau.getNumColumns();
- //d_tableau = copy;
- while(d_tableau.getNumColumns() < nc){
- d_tableau.increaseSize();
- }
- restoreErrorVariables(d_currentErrorVariables);
-
- reduceQueue();
-
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
-
- if(Debug.isOn("primal::consistent")){ d_linEq.debugEntireLinEqIsConsistent("primalFindModel2"); }
- Debug("primalFindModel") << "primalFindModel() end " << answer << endl;
-
- // The set of variables in conflict with their bounds will still be a subset of the
- // variables that are in conflict with their bounds in the beginning.
- // The basic variables are the same because of the copy.
- // Thus it is safe to not try to not recompute the queue of violating variables
-
- if(answer == Result::UNSAT){
- // This needs to be done in a different context level than the push
- ++d_statistics.d_primalUnsatCalls;
- }else{
- ++d_statistics.d_primalSatCalls;
- }
-
- d_primalCarry.clear();
-
- return answer;
-}
-
-/** Clears the ErrorMap and relase the resources associated with it.
- * There are a couple of error maps around
- */
-void SimplexDecisionProcedure::restoreErrorVariables(SimplexDecisionProcedure::ErrorMap& es){
- while(!es.empty()){
- ArithVar e = es.back();
-
- reassertErrorConstraint(e, es, false, false);
- es.pop_back();
- }
-}
-
-void SimplexDecisionProcedure::constructErrorVariables(){
- Assert(d_currentErrorVariables.empty());
- Assert(!d_queue.empty());
-
- for(ArithPriorityQueue::const_iterator iter = d_queue.begin(), end = d_queue.end(); iter != end; ++iter){
- ArithVar input = *iter;
-
- Assert(d_tableau.isBasic(input));
- Assert(!d_partialModel.assignmentIsConsistent(input));
-
- Assert(!d_currentErrorVariables.isKey(input));
-
- bool ub = d_partialModel.strictlyGreaterThanUpperBound(input, d_partialModel.getAssignment(input));
-
- Constraint original = ub ? d_partialModel.getUpperBoundConstraint(input)
- : d_partialModel.getLowerBoundConstraint(input);
-
- d_currentErrorVariables.set(input, ErrorInfo(input, ub, original));
-
- if(ub){
- d_partialModel.forceRelaxUpperBound(input);
- }else{
- d_partialModel.forceRelaxLowerBound(input);
- }
- Debug("primal") << "adding error variable (" << input << ", " << ", " << original <<") ";
- Debug("primal") << "ub "<< ub << " " << d_partialModel.getAssignment(input) << " " << original->getValue() <<")" << endl;
- d_currentErrorVariables.set(input, ErrorInfo(input, ub, original));
-
- // Constraint boundIsValue = d_constraintDatabase.getConstraint(bound, Equality, original->getValue());
- // boundIsValue->setPsuedoConstraint();
-
- // d_partialModel.setAssignment(bound, boundIsValue->getValue());
- // d_partialModel.setUpperBoundConstraint(boundIsValue);
- // d_partialModel.setLowerBoundConstraint(boundIsValue);
-
- // // if ub
- // // then error = x - boundIsValue
- // // else error = boundIsValue - x
-
- // ArithVar error = requestVariable();
-
- // DeltaRational diff = ub ?
- // d_partialModel.getAssignment(input) - boundIsValue->getValue() :
- // boundIsValue->getValue() - d_partialModel.getAssignment(input);
-
- // d_partialModel.setAssignment(error, diff);
-
- // vector<Rational> coeffs;
- // vector<ArithVar> variables;
- // variables.push_back(input);
- // coeffs.push_back(ub ? Rational(1) : Rational(-1));
- // variables.push_back(bound);
- // coeffs.push_back(ub ? Rational(-1) : Rational(1));
-
- // d_tableau.addRow(error, coeffs, variables);
-
-
- }
-
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
- if(Debug.isOn("primal::consistent")){ d_linEq.debugEntireLinEqIsConsistent("constructErrorVariables");}
- Assert(!d_currentErrorVariables.empty());
-}
-
-
-
-/** Returns true if it has found a row conflict for any of the error variables. */
-bool SimplexDecisionProcedure::checkForRowConflicts(){
- vector<ArithVar> inConflict;
- for(ErrorMap::const_iterator iter = d_currentErrorVariables.begin(), end = d_currentErrorVariables.end(); iter != end; ++iter){
- ArithVar error = *iter;
- const ErrorInfo& info = d_currentErrorVariables[error];
- if(d_tableau.isBasic(error) && !info.errorIsLeqZero(d_partialModel)){
-
- ArithVar x_j = info.isUpperbound() ?
- selectSlackLowerBound(error) :
- selectSlackUpperBound(error);
-
- if(x_j == ARITHVAR_SENTINEL ){
- inConflict.push_back(error);
- }
- }
- }
-
- if(!inConflict.empty()){
- while(!inConflict.empty()){
- ArithVar error = inConflict.back();
- inConflict.pop_back();
-
- reassertErrorConstraint(error, d_currentErrorVariables, false, true);
-
- Node conflict = d_currentErrorVariables[error].isUpperbound() ?
- generateConflictAboveUpperBound(error) :
- generateConflictBelowLowerBound(error);
- Assert(!conflict.isNull());
-
- d_currentErrorVariables.remove(error);
-
- reportConflict(conflict);
- }
- reconstructOptimizationFunction();
- return true;
- }else{
- return false;
- }
-}
-
-void SimplexDecisionProcedure::reassertErrorConstraint(ArithVar e, SimplexDecisionProcedure::ErrorMap& es, bool definitelyTrue, bool definitelyFalse){
- Assert(es.isKey(e));
- const ErrorInfo& info = es.get(e);
- Constraint original = info.getConstraint();
-
- if(info.isUpperbound()){
- d_partialModel.setUpperBoundConstraint(original);
- }else if(original->isLowerBound()){
- d_partialModel.setLowerBoundConstraint(original);
- }
-
- Assert(!definitelyTrue || d_partialModel.assignmentIsConsistent(e));
- Assert(!definitelyFalse || !d_partialModel.assignmentIsConsistent(e));
-}
-
-uint32_t SimplexDecisionProcedure::contractErrorVariables(bool guaranteedSuccess){
- uint32_t entrySize = d_currentErrorVariables.size();
- Debug("primal::contract") << "contractErrorVariables() begin : " << d_currentErrorVariables.size() << endl;
-
- std::vector<ArithVar> toRemove;
- for(ErrorMap::const_iterator iter = d_currentErrorVariables.begin(), end = d_currentErrorVariables.end(); iter != end; ++iter){
- ArithVar e = *iter;
- if(d_currentErrorVariables[e].errorIsLeqZero(d_partialModel)){
- toRemove.push_back(e);
- }
- }
-
- Assert(!guaranteedSuccess || !toRemove.empty());
-
- if(!toRemove.empty()){
- while(!toRemove.empty()){
- ArithVar e = toRemove.back();
- toRemove.pop_back();
- reassertErrorConstraint(e, d_currentErrorVariables, true, false);
- d_currentErrorVariables.remove(e);
- }
-
- reconstructOptimizationFunction();
- }
-
- Debug("primal::contract") << "contractErrorVariables() end : " << d_currentErrorVariables.size() << endl;
-
- uint32_t exitSize = d_currentErrorVariables.size();
-
- Assert(exitSize <= entrySize);
- Assert(!guaranteedSuccess|| exitSize < entrySize);
- return entrySize - exitSize;
-}
-
-void SimplexDecisionProcedure::removeOptimizationFunction(){
- Assert(d_optRow != ARITHVAR_SENTINEL);
- Assert(d_tableau.isBasic(d_optRow));
-
- d_tableau.removeBasicRow(d_optRow);
- releaseVariable(d_optRow);
-
- d_optRow = ARITHVAR_SENTINEL;
- d_negOptConstant = d_DELTA_ZERO;
-
- Assert(d_optRow == ARITHVAR_SENTINEL);
-}
-
-void SimplexDecisionProcedure::constructOptimizationFunction(){
- Assert(d_optRow == ARITHVAR_SENTINEL);
- Assert(d_negOptConstant == d_DELTA_ZERO);
-
- d_optRow = requestVariable();
-
-
- std::vector<Rational> coeffs;
- std::vector<ArithVar> variables;
- for(ErrorMap::const_iterator iter = d_currentErrorVariables.begin(), end = d_currentErrorVariables.end(); iter != end; ++iter){
- ArithVar e = *iter;
-
- if(d_currentErrorVariables[e].isUpperbound()){
- coeffs.push_back(Rational(1));
- variables.push_back(e);
- d_negOptConstant = d_negOptConstant + (d_currentErrorVariables[e].getConstraint()->getValue());
- }else{
- coeffs.push_back(Rational(-1));
- variables.push_back(e);
- d_negOptConstant = d_negOptConstant - (d_currentErrorVariables[e].getConstraint()->getValue());
- }
- }
- d_tableau.addRow(d_optRow, coeffs, variables);
-
- DeltaRational newAssignment = d_linEq.computeRowValue(d_optRow, false);
- d_partialModel.setAssignment(d_optRow, newAssignment);
-
- if(Debug.isOn("primal::tableau")){ d_linEq.debugCheckTableau(); }
-
-
- if(Debug.isOn("primal::consistent")){
- d_linEq.debugEntireLinEqIsConsistent("constructOptimizationFunction");
- }
-
- d_pivotsSinceOptProgress = 0;
- d_pivotsSinceErrorProgress = 0;
-
- Assert(d_optRow != ARITHVAR_SENTINEL);
-}
-
-void SimplexDecisionProcedure::reconstructOptimizationFunction(){
- removeOptimizationFunction();
- constructOptimizationFunction();
-}
-
-
-
-/* TODO:
- * Very naive implementation. Recomputes everything every time.
- * Currently looks for the variable that can decrease the optimization function the most.
- *
- */
-SimplexDecisionProcedure::PrimalResponse SimplexDecisionProcedure::primalCheck()
-{
- Debug("primal") << "primalCheck() begin" << endl;
-
- ArithVar leaving = ARITHVAR_SENTINEL;
- ArithVar entering = ARITHVAR_SENTINEL;
- DeltaRational leavingShift = d_DELTA_ZERO; // The amount the leaving variable can change by without making the tableau inconsistent
- DeltaRational leavingDelta = d_DELTA_ZERO; // The amount the optimization function changes by selecting leaving
-
- Assert(d_improvementCandidates.empty());
-
- for( Tableau::RowIterator ri = d_tableau.basicRowIterator(d_optRow); !ri.atEnd(); ++ri){
- const Tableau::Entry& e = *ri;
-
- ArithVar curr = e.getColVar();
- if(curr == d_optRow){ continue; }
-
-
- int sgn = e.getCoefficient().sgn();
- Assert(sgn != 0);
- if( (sgn < 0 && d_partialModel.strictlyBelowUpperBound(curr)) ||
- (sgn > 0 && d_partialModel.strictlyAboveLowerBound(curr)) ){
-
- d_improvementCandidates.push_back(&e);
- }
- }
-
- if(d_improvementCandidates.empty()){
- Debug("primal") << "primalCheck() end : global" << endl;
- return GlobalMinimum; // No variable in the optimization function can be improved
- }
-
- DeltaRational minimumShift;
- DeltaRational currShift;
- for(EntryVector::const_iterator ci = d_improvementCandidates.begin(), end_ci = d_improvementCandidates.end(); ci != end_ci; ++ci){
- const Tableau::Entry& e = *(*ci);
- ArithVar curr = e.getColVar();
-
- ArithVar currEntering;
- bool progress;
-
- minimumShift = (leaving == ARITHVAR_SENTINEL ) ? leavingDelta/(e.getCoefficient().abs()) : d_DELTA_ZERO;
- int sgn = e.getCoefficient().sgn();
- computeShift(curr, sgn < 0, progress, currEntering, currShift, minimumShift);
-
- if(currEntering == ARITHVAR_SENTINEL){
- d_improvementCandidates.clear();
-
- Debug("primal") << "primalCheck() end : unbounded" << endl;
- d_primalCarry.d_unbounded = curr;
- return FoundUnboundedVariable;
- }else if(progress) {
- leaving = curr;
- leavingShift = currShift;
- leavingDelta = currShift * e.getCoefficient();
- entering = currEntering;
-
- Assert(leavingDelta < d_DELTA_ZERO);
-
- const int RECHECK_PERIOD = 10;
- if(d_pivotsSinceErrorProgress % RECHECK_PERIOD != 0){
- // we can make progress, stop
- break;
- }
- }
- }
-
- if(leaving == ARITHVAR_SENTINEL){
- cout << "Nothing can make progress " << endl;
-
- const uint32_t THRESHOLD = 20;
- if(d_pivotsSinceOptProgress <= THRESHOLD){
-
- int index = rand() % d_improvementCandidates.size();
- leaving = (*d_improvementCandidates[index]).getColVar();
- entering = selectFirstValid(leaving, (*d_improvementCandidates[index]).getCoefficient().sgn() < 0);
- }else{ // Bland's rule
- bool increasing;
- for(EntryVector::const_iterator ci = d_improvementCandidates.begin(), end_ci = d_improvementCandidates.end(); ci != end_ci; ++ci){
- const Tableau::Entry& e = *(*ci);
- ArithVar curr = e.getColVar();
- leaving = (leaving == ARITHVAR_SENTINEL) ? curr : minVarOrder(*this, curr, leaving);
- if(leaving == curr){
- increasing = (e.getCoefficient().sgn() < 0);
- }
- }
-
- entering = selectMinimumValid(leaving, increasing);
- }
- Assert(leaving != ARITHVAR_SENTINEL);
- Assert(entering != ARITHVAR_SENTINEL);
-
- d_primalCarry.d_leaving = leaving;
- d_primalCarry.d_entering = entering;
-
- d_primalCarry.d_nextEnteringValue = d_partialModel.getAssignment(entering);
-
- Debug("primal") << "primalCheck() end : no progress made " << leaving << " to " << entering << " (" << d_pivotsSinceOptProgress << ")"<< endl;
- d_improvementCandidates.clear();
- return NoProgressOnLeaving;
- }else{
- const Tableau::Entry& enterLeavingEntry = d_tableau.findEntry(d_tableau.basicToRowIndex(entering), leaving);
- Assert(!enterLeavingEntry.blank());
-
- d_primalCarry.d_leaving = leaving;
- d_primalCarry.d_entering = entering;
- d_primalCarry.d_nextEnteringValue = d_partialModel.getAssignment(entering)
- + leavingShift * enterLeavingEntry.getCoefficient();
-
- Debug("primal") << "primalCheck() end : progress" << endl
- << leaving << " to " << entering << " ~ "
- << d_partialModel.getAssignment(leaving) << " ~ " << leavingShift
- << " ~ " << enterLeavingEntry.getCoefficient()
- << " ~ " << d_primalCarry.d_nextEnteringValue << endl;
-
- d_improvementCandidates.clear();
- return MakeProgressOnLeaving;
- }
-
- // anyProgress = true;
-
- // DeltaRational currDelta = currShift * e.getCoefficient();
-
- // int cmp = currDelta.cmp(leavingDelta);
-
- // // Cases:
- // // 1) No candidate yet,
- // // 2) there is a candidate with a strictly better update, or
- // // 3) there is a candidate with the same update value that has a smaller value in the variable ordering.
- // //
- // // Case 3 covers Bland's rule.
- // if(entering == ARITHVAR_SENTINEL || cmp < 0){
- // leaving = curr;
- // }else if( cmp == 0 ){
- // leaving = minVarOrder(*this, curr, leaving);
- // }
-
- // if(leaving == curr){
- // leavingShift = currShift;
- // leavingDelta = currDelta;
- // entering = currEntering;
- // }
- // }
- // }
-
- // if(leaving == ARITHVAR_SENTINEL){
- // Debug("primal") << "primalCheck() end : global" << endl;
- // return GlobalMinimum; // No variable in the optimization function can be improved
- // }else{
- // const Tableau::Entry& enterLeavingEntry = d_tableau.findEntry(d_tableau.basicToRowIndex(entering), leaving);
- // Assert(!enterLeavingEntry.blank());
-
- // d_primalCarry.d_leaving = leaving;
- // d_primalCarry.d_entering = entering;
- // d_primalCarry.d_nextEnteringValue = d_partialModel.getAssignment(entering)
- // + leavingShift * enterLeavingEntry.getCoefficient();
-
- // Debug("primal") << "primalCheck() end : progress" << endl
- // << leaving << " to " << entering << " ~ "
- // << d_partialModel.getAssignment(leaving) << " ~ " << leavingShift
- // << " ~ " << enterLeavingEntry.getCoefficient()
- // << " ~ " << d_primalCarry.d_nextEnteringValue << endl;
- // return MakeProgressOnLeaving;
- // }
-}
-
-ArithVar SimplexDecisionProcedure::selectMinimumValid(ArithVar v, bool increasing){
- ArithVar minimum = ARITHVAR_SENTINEL;
- for(Tableau::ColIterator colIter = d_tableau.colIterator(v);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow) continue;
-
-
- int esgn = e.getCoefficient().sgn();
- bool basicInc = (increasing == (esgn > 0));
-
- if(!(basicInc ? d_partialModel.strictlyBelowUpperBound(basic) :
- d_partialModel.strictlyAboveLowerBound(basic))){
- if(minimum == ARITHVAR_SENTINEL){
- minimum = basic;
- }else{
- minimum = minVarOrder(*this, basic, minimum);
- }
- }
- }
- return minimum;
-}
-
-ArithVar SimplexDecisionProcedure::selectFirstValid(ArithVar v, bool increasing){
- ArithVar minimum = ARITHVAR_SENTINEL;
-
- for(Tableau::ColIterator colIter = d_tableau.colIterator(v);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow) continue;
-
- int esgn = e.getCoefficient().sgn();
- bool basicInc = (increasing == (esgn > 0));
-
- if(!(basicInc ? d_partialModel.strictlyBelowUpperBound(basic) :
- d_partialModel.strictlyAboveLowerBound(basic))){
- if(minimum == ARITHVAR_SENTINEL){
- minimum = basic;
- }else{
- minimum = minRowLength(*this, basic, minimum);
- }
- }
- }
- return minimum;
-}
-
-
-
-void SimplexDecisionProcedure::computeShift(ArithVar leaving, bool increasing, bool& progress, ArithVar& entering, DeltaRational& shift, const DeltaRational& minimumShift){
- Assert(increasing ? (minimumShift >= d_DELTA_ZERO) : (minimumShift <= d_DELTA_ZERO) );
-
- static int instance = 0;
- Debug("primal") << "computeshift " << ++instance << " " << leaving << endl;
-
- // The selection for the leaving variable
- entering = ARITHVAR_SENTINEL;
-
- // no progress is initially made
- progress = false;
-
- bool bounded = false;
-
- if(increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving)){
- const DeltaRational& assignment = d_partialModel.getAssignment(leaving);
-
- bounded = true;
-
- DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
- Assert(increasing ? diff.sgn() >=0 : diff.sgn() <= 0);
- if((increasing) ? (diff < minimumShift) : ( diff > minimumShift)){
- Assert(!progress);
- entering = leaving; // My my my, what an ugly hack
- return; // no progress is possible stop
- }
- }
-
- // shift has a meaningful value once entering has a meaningful value
- // if increasing,
- // then shift > minimumShift >= 0
- // else shift < minimumShift <= 0
- //
- // Maintain the following invariant:
- //
- // if increasing,
- // if e_ij > 0, diff >= shift > minimumShift >= 0
- // if e_ij < 0, diff >= shift > minimumShift >= 0
- // if !increasing,
- // if e_ij > 0, diff <= shift < minimumShift <= 0
- // if e_ij < 0, diff <= shift < minimumShift <= 0
- // if increasing == (e_ij > 0), diff = (d_partialModel.getUpperBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient()
- // if increasing != (e_ij > 0), diff = (d_partialModel.getLowerBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient()
-
- for(Tableau::ColIterator colIter = d_tableau.colIterator(leaving);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
-
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow) continue;
-
- int esgn = e.getCoefficient().sgn();
- bool basicInc = (increasing == (esgn > 0));
- // If both are true, increasing the variable entering increases the basic variable
- // If both are false, the entering variable is decreasing, but the coefficient is negative and the basic variable is increasing
- // If exactly one is false, the basic variable is decreasing.
-
- Debug("primal::shift") << basic << " " << d_partialModel.hasUpperBound(basic) << " "
- << d_partialModel.hasLowerBound(basic) << " "
- << e.getCoefficient() << endl;
-
- if( (basicInc && d_partialModel.hasUpperBound(basic))||
- (!basicInc && d_partialModel.hasLowerBound(basic))){
-
- if(!(basicInc ? d_partialModel.strictlyBelowUpperBound(basic) :
- d_partialModel.strictlyAboveLowerBound(basic))){
- // diff == 0, as diff > minimumShift >= 0 or diff < minimumShift <= 0
- Assert(!progress);
- entering = basic;
- return;
- }else{
- DeltaRational diff = basicInc ?
- (d_partialModel.getUpperBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient() :
- (d_partialModel.getLowerBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient();
-
- if( entering == ARITHVAR_SENTINEL ){
- if(increasing ? (diff <= minimumShift) : (diff >= minimumShift)){
- Assert(!progress);
- entering = basic;
- return;
- }else{
- Assert(increasing ? (diff > minimumShift) : (diff < minimumShift));
- shift = diff;
- entering = basic;
- bounded = true;
- }
- }else{
- if( increasing ? (diff < shift) : diff > shift){
- // a new min for increasing
- // a new max for decreasing
-
- if(increasing ? (diff <= minimumShift) : (diff >= minimumShift)){
- Assert(!progress);
- entering = basic;
- return;
- }else{
- Assert(increasing ? (diff > minimumShift) : (diff < minimumShift));
- shift = diff;
- entering = basic;
- }
- }
- }
- }
- }
- }
-
- if(!bounded){
- // A totally unbounded variable
- Assert(entering == ARITHVAR_SENTINEL);
- progress = true;
- return;
- }else if(entering == ARITHVAR_SENTINEL){
- // We have a variable that is bounded only by its maximum
- for(Tableau::ColIterator colIter = d_tableau.colIterator(leaving);!colIter.atEnd(); ++colIter){
- const Tableau::Entry& e = *colIter;
-
- ArithVar basic = d_tableau.rowIndexToBasic(e.getRowIndex());
- if(basic == d_optRow){
- continue;
- } else{
- entering = basic;
- break;
- }
- }
- Assert(entering != ARITHVAR_SENTINEL);
-
- Assert(increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving));
-
- const DeltaRational& assignment = d_partialModel.getAssignment(leaving);
- DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
-
- shift = diff;
-
- Assert(increasing ? shift.sgn() >=0 : shift.sgn() <= 0);
- Assert(increasing ? shift > minimumShift : shift < minimumShift);
-
- progress = true;
- return;
- }else{
- Assert(bounded);
- progress = true;
-
- if((increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving) )){
- Assert(entering != ARITHVAR_SENTINEL);
- const DeltaRational& assignment = d_partialModel.getAssignment(leaving);
- DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
- if((increasing) ? (diff < shift) : ( diff > shift)){
- shift = diff;
- }
- }
-
- Assert(increasing ? shift.sgn() >=0 : shift.sgn() <= 0);
- Assert(increasing ? shift > minimumShift : shift < minimumShift);
- return;
- }
-
-
- // if(! bounded ||
- // (increasing && diff < shift) || // a new min for increasing
- // (!increasing && diff > shift)){ // a new max for decreasing
- // bounded = true;
- // shift = diff;
- // entering = basic;
- // }
- // }
-
- // if(notAtTheBound && !blandMode){
- // DeltaRational diff = basicInc ?
- // (d_partialModel.getUpperBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient() :
- // (d_partialModel.getLowerBound(basic) - d_partialModel.getAssignment(basic)) / e.getCoefficient();
-
- // if(! bounded ||
- // (increasing && diff < shift) || // a new min for increasing
- // (!increasing && diff > shift)){ // a new max for decreasing
- // bounded = true;
- // shift = diff;
- // entering = basic;
- // }
- // }else if (!notAtTheBound) { // basic is already exactly at the bound
- // if(!blandMode){ // Enter into using Bland's rule
- // blandMode = true;
- // bounded = true;
- // shift = d_DELTA_ZERO;
- // entering = basic;
- // }else{
- // entering = minVarOrder(*this, entering, basic); // Bland's rule.
- // }
- // }
- // else this basic variable cannot be violated by increasing/decreasing entering
-
-
-
-
- // if(!blandMode && (increasing ? d_partialModel.hasUpperBound(leaving) : d_partialModel.hasLowerBound(leaving) )){
- // Assert(entering != ARITHVAR_SENTINEL);
- // bounded = true;
- // DeltaRational diff = increasing ? d_partialModel.getUpperBound(leaving) - assignment : d_partialModel.getLowerBound(leaving) - assignment;
- // if((increasing) ? (diff < shift) : ( diff > shift)){
- // shift = diff;
- // }
- // }
-
- // Assert(increasing ? shift.sgn() >=0 : shift.sgn() <= 0);
-
- // return shift;
-}
-
-
-/**
- * Given an variable on the optimization row that can be used to decrease the value of the optimization function
- * arbitrarily and an optimization function that is strictly positive in the current model,
- * driveOptToZero updates the value of unbounded s.t. the value of d_opt is exactly 0.
- */
-void SimplexDecisionProcedure::driveOptToZero(ArithVar unbounded){
- Assert(!belowThreshold());
-
- const Tableau::Entry& e = d_tableau.findEntry(d_tableau.basicToRowIndex(d_optRow), unbounded);
- Assert(!e.blank());
-
- DeltaRational theta = (d_negOptConstant-d_partialModel.getAssignment(d_optRow))/ (e.getCoefficient());
- Assert((e.getCoefficient().sgn() > 0) ? (theta.sgn() < 0) : (theta.sgn() > 0));
-
- DeltaRational newAssignment = d_partialModel.getAssignment(unbounded) + theta;
- d_linEq.update(unbounded, newAssignment);
-
- if(Debug.isOn("primal::consistent")){ Assert(d_linEq.debugEntireLinEqIsConsistent("driveOptToZero")); }
-
- Assert(belowThreshold());
-}
diff --git a/src/theory/arith/simplex-converge.h b/src/theory/arith/simplex-converge.h
deleted file mode 100644
index dac3a9b49..000000000
--- a/src/theory/arith/simplex-converge.h
+++ /dev/null
@@ -1,531 +0,0 @@
-/********************* */
-/*! \file simplex.h
- ** \verbatim
- ** Original author: taking
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief This is an implementation of the Simplex Module for the Simplex for DPLL(T) decision procedure.
- **
- ** This implements the Simplex module for the Simpelx for DPLL(T) decision procedure.
- ** See the Simplex for DPLL(T) technical report for more background.(citation?)
- ** This shares with the theory a Tableau, and a PartialModel that:
- ** - satisfies the equalities in the Tableau, and
- ** - the assignment for the non-basic variables satisfies their bounds.
- ** This is required to either produce a conflict or satisifying PartialModel.
- ** Further, we require being told when a basic variable updates its value.
- **
- ** During the Simplex search we maintain a queue of variables.
- ** The queue is required to contain all of the basic variables that voilate their bounds.
- ** As elimination from the queue is more efficient to be done lazily,
- ** we do not maintain that the queue of variables needs to be only basic variables or only variables that satisfy their bounds.
- **
- ** The simplex procedure roughly follows Alberto's thesis. (citation?)
- ** There is one round of selecting using a heuristic pivoting rule. (See PreferenceFunction Documentation for the available options.)
- ** The non-basic variable is the one that appears in the fewest pivots. (Bruno says that Leonardo invented this first.)
- ** After this, Bland's pivot rule is invoked.
- **
- ** During this proccess, we periodically inspect the queue of variables to
- ** 1) remove now extraneous extries,
- ** 2) detect conflicts that are "waiting" on the queue but may not be detected by the current queue heuristics, and
- ** 3) detect multiple conflicts.
- **
- ** Conflicts are greedily slackened to use the weakest bounds that still produce the conflict.
- **
- ** Extra things tracked atm: (Subject to change at Tim's whims)
- ** - A superset of all of the newly pivoted variables.
- ** - A queue of additional conflicts that were discovered by Simplex.
- ** These are theory valid and are currently turned into lemmas
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__ARITH__SIMPLEX_H
-#define __CVC4__THEORY__ARITH__SIMPLEX_H
-
-#include "theory/arith/arithvar.h"
-#include "theory/arith/arith_priority_queue.h"
-#include "theory/arith/delta_rational.h"
-#include "theory/arith/matrix.h"
-#include "theory/arith/partial_model.h"
-#include "theory/arith/linear_equality.h"
-
-#include "context/cdlist.h"
-
-#include "util/dense_map.h"
-#include "options/options.h"
-#include "util/stats.h"
-#include "util/result.h"
-
-#include <queue>
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-
-class SimplexDecisionProcedure {
-private:
- ArithVar d_conflictVariable;
- DenseSet d_successes;
-
- /** Linear equality module. */
- LinearEqualityModule& d_linEq;
-
- /**
- * Manages information about the assignment and upper and lower bounds on
- * variables.
- * Partial model matches that in LinearEqualityModule.
- */
- ArithPartialModel& d_partialModel;
-
- /**
- * Stores the linear equalities used by Simplex.
- * Tableau from the LinearEquality module.
- */
- Tableau& d_tableau;
-
- /** Contains a superset of the basic variables in violation of their bounds. */
- ArithPriorityQueue d_queue;
-
- /** Number of variables in the system. This is used for tuning heuristics. */
- ArithVar d_numVariables;
-
- /** This is the call back channel for Simplex to report conflicts. */
- NodeCallBack& d_conflictChannel;
-
- /** Maps a variable to how many times they have been used as a pivot in the simplex search. */
- DenseMultiset d_pivotsInRound;
-
- /** Stores to the DeltaRational constant 0. */
- DeltaRational d_DELTA_ZERO;
-
- //TODO make an option
- const static uint32_t MAX_ITERATIONS = 20;
-
-
- /** Used for requesting d_opt, bound and error variables for primal.*/
- ArithVarMalloc& d_arithVarMalloc;
-
- /** Used for constructing temporary variables, bound and error variables for primal.*/
- ConstraintDatabase& d_constraintDatabase;
-
-public:
- SimplexDecisionProcedure(LinearEqualityModule& linEq,
- NodeCallBack& conflictChannel,
- ArithVarMalloc& variables,
- ConstraintDatabase& constraintDatabase);
-
- /**
- * This must be called when the value of a basic variable may now voilate one
- * of its bounds.
- */
- void updateBasic(ArithVar x){
- d_queue.enqueueIfInconsistent(x);
- }
-
- /**
- * Tries to update the assignments of variables such that all of the
- * assignments are consistent with their bounds.
- * This is done by a simplex search through the possible bases of the tableau.
- *
- * If all of the variables can be made consistent with their bounds
- * SAT is returned. Otherwise UNSAT is returned, and at least 1 conflict
- * was reported on the conflictCallback passed to the Module.
- *
- * Tableau pivoting is performed so variables may switch from being basic to
- * nonbasic and vice versa.
- *
- * Corresponds to the "check()" procedure in [Cav06].
- */
- Result::Sat dualFindModel(bool exactResult);
-
-
- /**
- * Tries to update the assignments of the variables s.t. all of the assignments
- * are consistent with their bounds.
- *
- * This is a REALLY heavy hammer consider calling dualFindModel(false) first.
- *
- * !!!!!!!!!!!!!IMPORTANT!!!!!!!!!!!!!!
- * This procedure needs to temporarily relax contraints to contruct a satisfiable system.
- * To do this, it is going to do a sat push.
- */
- Result::Sat primalFindModel();
-
-private:
-
-
- /**
- * A PreferenceFunction takes a const ref to the SimplexDecisionProcedure,
- * and 2 ArithVar variables and returns one of the ArithVar variables potentially
- * using the internals of the SimplexDecisionProcedure.
- *
- * Both ArithVar must be non-basic in d_tableau.
- */
- typedef ArithVar (*PreferenceFunction)(const SimplexDecisionProcedure&, ArithVar, ArithVar);
-
- /**
- * minVarOrder is a PreferenceFunction for selecting the smaller of the 2 ArithVars.
- * This PreferenceFunction is used during the VarOrder stage of
- * findModel.
- */
- static ArithVar minVarOrder(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
-
- /**
- * minRowCount is a PreferenceFunction for selecting the variable with the smaller
- * row count in the tableau.
- *
- * This is a heuristic rule and should not be used
- * during the VarOrder stage of findModel.
- */
- static ArithVar minColLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
- static ArithVar minRowLength(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
-
- /**
- * minBoundAndRowCount is a PreferenceFunction for preferring a variable
- * without an asserted bound over variables with an asserted bound.
- * If both have bounds or both do not have bounds,
- * the rule falls back to minRowCount(...).
- *
- * This is a heuristic rule and should not be used
- * during the VarOrder stage of findModel.
- */
- static ArithVar minBoundAndRowCount(const SimplexDecisionProcedure& simp, ArithVar x, ArithVar y);
-
-
- /**
- * This is the main simplex for DPLL(T) loop.
- * It runs for at most maxIterations.
- *
- * Returns true iff it has found a conflict.
- * d_conflictVariable will be set and the conflict for this row is reported.
- */
- bool searchForFeasibleSolution(uint32_t maxIterations);
-
- enum SearchPeriod {BeforeDiffSearch, DuringDiffSearch, AfterDiffSearch, DuringVarOrderSearch, AfterVarOrderSearch};
-
- bool findConflictOnTheQueue(SearchPeriod period);
-
-
- /**
- * Given the basic variable x_i,
- * this function finds the smallest nonbasic variable x_j in the row of x_i
- * in the tableau that can "take up the slack" to let x_i satisfy its bounds.
- * This returns ARITHVAR_SENTINEL if none exists.
- *
- * More formally one of the following conditions must be satisfied:
- * - lowerBound && a_ij < 0 && assignment(x_j) < upperbound(x_j)
- * - lowerBound && a_ij > 0 && assignment(x_j) > lowerbound(x_j)
- * - !lowerBound && a_ij > 0 && assignment(x_j) < upperbound(x_j)
- * - !lowerBound && a_ij < 0 && assignment(x_j) > lowerbound(x_j)
- *
- */
- template <bool lowerBound> ArithVar selectSlack(ArithVar x_i, PreferenceFunction pf);
- ArithVar selectSlackLowerBound(ArithVar x_i, PreferenceFunction pf = minVarOrder) {
- return selectSlack<true>(x_i, pf);
- }
- ArithVar selectSlackUpperBound(ArithVar x_i, PreferenceFunction pf = minVarOrder) {
- return selectSlack<false>(x_i, pf);
- }
- /**
- * Returns the smallest basic variable whose assignment is not consistent
- * with its upper and lower bounds.
- */
- ArithVar selectSmallestInconsistentVar();
-
- /**
- * Given a non-basic variable that is know to not be updatable
- * to a consistent value, construct and return a conflict.
- * Follows section 4.2 in the CAV06 paper.
- */
- Node generateConflictAboveUpperBound(ArithVar conflictVar);
- Node generateConflictBelowLowerBound(ArithVar conflictVar);
-
-public:
- void increaseMax() {d_numVariables++;}
-
-
- void clearQueue() {
- d_queue.clear();
- }
-
-
- bool debugIsInCollectionQueue(ArithVar var) const{
- Assert(d_queue.inCollectionMode());
- return d_queue.collectionModeContains(var);
- }
-
- void reduceQueue(){
- d_queue.reduce();
- }
-
- ArithPriorityQueue::const_iterator queueBegin() const{
- return d_queue.begin();
- }
-
- ArithPriorityQueue::const_iterator queueEnd() const{
- return d_queue.end();
- }
-
-private:
-
- /** Reports a conflict to on the output channel. */
- void reportConflict(Node conflict){
- d_conflictChannel(conflict);
- ++(d_statistics.d_simplexConflicts);
- }
-
- template <bool above>
- inline bool isAcceptableSlack(int sgn, ArithVar nonbasic){
- return
- ( above && sgn < 0 && d_partialModel.strictlyBelowUpperBound(nonbasic)) ||
- ( above && sgn > 0 && d_partialModel.strictlyAboveLowerBound(nonbasic)) ||
- (!above && sgn > 0 && d_partialModel.strictlyBelowUpperBound(nonbasic)) ||
- (!above && sgn < 0 && d_partialModel.strictlyAboveLowerBound(nonbasic));
- }
-
- /**
- * Checks a basic variable, b, to see if it is in conflict.
- * If a conflict is discovered a node summarizing the conflict is returned.
- * Otherwise, Node::null() is returned.
- */
- Node checkBasicForConflict(ArithVar b);
-
- Node weakenConflict(bool aboveUpper, ArithVar basicVar);
- Constraint weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic);
-
- /** Gets a fresh variable from TheoryArith. */
- ArithVar requestVariable(){
- return d_arithVarMalloc.request();
- }
-
- /** Releases a requested variable from TheoryArith.*/
- void releaseVariable(ArithVar v){
- d_arithVarMalloc.release(v);
- }
-
-
- /** An error info keeps the information associated with the construction of an ErrorVariable. */
- class ErrorInfo {
- private:
- /** The variable for which the error variable was constructed.*/
- ArithVar d_variable;
-
- // If false -> lowerbound
- bool d_upperbound;
-
- /** The violated constraint this was constructed to try to satisfy.*/
- Constraint d_violated;
-
- public:
- ErrorInfo(ArithVar error, bool ub, const Constraint original)
- : d_variable(error), d_upperbound(ub), d_violated(original) {}
-
- ErrorInfo() :
- d_variable(ARITHVAR_SENTINEL), d_upperbound(false), d_violated(NullConstraint){}
-
- inline ArithVar getVariable() const {
- return d_variable;
- }
-
- inline bool isUpperbound() const {
- return d_upperbound;
- }
-
- inline bool errorIsLeqZero(const ArithPartialModel& d_pm) const{
- return isUpperbound() ?
- (d_pm.getAssignment(d_variable) <= d_violated->getValue()) :
- (d_pm.getAssignment(d_variable) >= d_violated->getValue());
- }
-
- inline Constraint getConstraint() const {
- return d_violated;
- }
-
- inline DeltaRational getErrorAmount(const ArithPartialModel& d_pm) const {
- return isUpperbound() ?
- (d_pm.getAssignment(d_variable) - d_violated->getValue()) :
- (d_violated->getValue() - d_pm.getAssignment(d_variable));
- }
- };
-
- typedef DenseMap<ErrorInfo> ErrorMap;
-
- /** A map from the error variables to the associated ErrorInfo.*/
- ErrorMap d_currentErrorVariables;
-
- /** The optimization function is implicitly defined as
- * f_i = d_optRow - d_negOptConstant
- *
- * d_optRow is a basic variable in the tableau.
- * The tableau maintains that it is equal to the sum of -1^{!ub} * the error variables in
- * d_currentErrorVariables.
- *
- * d_negOptConstant is explicitly the negation of the sum of the bounds that were violated
- *
- * assignment(f_i) <= 0 iff assignment(d_optRow) <= d_negOptConstant
- */
- /** The variable for the variable part of the optimization function.*/
- ArithVar d_optRow;
-
- /** The constant part of the optimization function.*/
- DeltaRational d_negOptConstant;
-
- inline bool belowThreshold() const {
- return d_partialModel.getAssignment(d_optRow) <= d_negOptConstant;
- }
-
- /**
- * A PrimalResponse represents the state that the primal simplex solver is in.
- */
- enum PrimalResponse {
- // The optimization can decrease arbitrarily on some variable in the function
- FoundUnboundedVariable,
-
- // The optimization function has reached a threshold value and is checking back in
- ReachedThresholdValue,
-
- // Simplex has used up its pivot bound and is checking back in with its caller
- UsedMaxPivots,
-
- //Simplex can make progress on the pair of entering and leaving variables
- MakeProgressOnLeaving,
-
- //Simplex is not at a minimum but no leaving variable can be changed to help
- NoProgressOnLeaving,
-
- // Simplex has reached a minimum for its optimization function
- GlobalMinimum
- };
-
- /**
- * These fields are for sticking information for passing information back with the PrimalRespones.
- * These fields should be ignored as unsafe/unknown unless you have a PrimalResponse that states
- * the field makes sense.
- */
- struct PrimalPassBack {
- public:
- /**
- * A variable s.t. its value can be increased/decreased arbitrarily to change the optimization function
- * arbitrarily low.
- */
- ArithVar d_unbounded;
-
- /** The leaving variable selection for primal simplex. */
- ArithVar d_leaving;
-
- /** The entering variable selection for primal simplex. */
- ArithVar d_entering;
-
- /** The new value for the leaving variable value for primal simplex.*/
- DeltaRational d_nextEnteringValue;
-
- PrimalPassBack() { clear(); }
- void clear(){
- d_unbounded = (d_leaving = (d_entering = ARITHVAR_SENTINEL));
- d_nextEnteringValue = DeltaRational();
- }
-
- bool isClear() const {
- return d_unbounded == ARITHVAR_SENTINEL &&
- d_leaving == ARITHVAR_SENTINEL &&
- d_entering == ARITHVAR_SENTINEL &&
- d_nextEnteringValue.sgn() == 0;
- }
- } d_primalCarry;
-
- uint32_t d_pivotsSinceErrorProgress;
- uint32_t d_pivotsSinceOptProgress;
- uint32_t d_pivotsSinceLastCheck;
-
- typedef std::vector< const Tableau::Entry* > EntryVector;
- EntryVector d_improvementCandidates;
-
- PrimalResponse primal(uint32_t maxIterations);
- PrimalResponse primalCheck();
- Result::Sat primalConverge(int depth);
- void driveOptToZero(ArithVar unbounded);
- uint32_t contractErrorVariables(bool guaranteedSuccess);
- bool checkForRowConflicts();
- void restoreErrorVariables(ErrorMap& es);
- void constructErrorVariables();
- void constructOptimizationFunction();
- void removeOptimizationFunction();
- void reconstructOptimizationFunction();
- ArithVar selectMinimumValid(ArithVar v, bool increasing);
- ArithVar selectFirstValid(ArithVar v, bool increasing);
-
- void reassertErrorConstraint(ArithVar e, ErrorMap& es, bool definitelyTrue, bool definitelyFalse);
- void computeShift(ArithVar leaving, bool increasing, bool& progress, ArithVar& entering, DeltaRational& shift, const DeltaRational& minimumShift);
-
- /** These fields are designed to be accessible to TheoryArith methods. */
- class Statistics {
- public:
- IntStat d_statUpdateConflicts;
-
- TimerStat d_findConflictOnTheQueueTime;
-
- IntStat d_attemptBeforeDiffSearch, d_successBeforeDiffSearch;
- IntStat d_attemptAfterDiffSearch, d_successAfterDiffSearch;
- IntStat d_attemptDuringDiffSearch, d_successDuringDiffSearch;
- IntStat d_attemptDuringVarOrderSearch, d_successDuringVarOrderSearch;
- IntStat d_attemptAfterVarOrderSearch, d_successAfterVarOrderSearch;
-
- IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings;
- TimerStat d_weakenTime;
-
-
- IntStat d_simplexConflicts;
-
- // Primal stuffs
- TimerStat d_primalTimer;
- TimerStat d_internalTimer;
-
- IntStat d_primalCalls;
- IntStat d_primalSatCalls;
- IntStat d_primalUnsatCalls;
-
- IntStat d_primalPivots;
- IntStat d_primalImprovingPivots;
-
- IntStat d_primalThresholdReachedPivot;
- IntStat d_primalThresholdReachedPivot_dropped;
-
- IntStat d_primalReachedMaxPivots;
- IntStat d_primalReachedMaxPivots_contractMadeProgress;
- IntStat d_primalReachedMaxPivots_checkForConflictWorked;
-
-
- IntStat d_primalGlobalMinimum;
- IntStat d_primalGlobalMinimum_rowConflictWorked;
- IntStat d_primalGlobalMinimum_firstHalfWasSat;
- IntStat d_primalGlobalMinimum_firstHalfWasUnsat;
- IntStat d_primalGlobalMinimum_contractMadeProgress;
-
-
- IntStat d_unboundedFound;
- IntStat d_unboundedFound_drive;
- IntStat d_unboundedFound_dropped;
-
-
- Statistics();
- ~Statistics();
- };
-
- Statistics d_statistics;
-
-};/* class SimplexDecisionProcedure */
-
-}/* CVC4::theory::arith namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__ARITH__SIMPLEX_H */
-
diff --git a/src/theory/arith/simplex.cpp b/src/theory/arith/simplex.cpp
index 02e49258c..a160f4fe2 100644
--- a/src/theory/arith/simplex.cpp
+++ b/src/theory/arith/simplex.cpp
@@ -130,6 +130,8 @@ void SimplexDecisionProcedure::tearDownInfeasiblityFunction(TimerStat& timer, Ar
Assert(tmp != ARITHVAR_SENTINEL);
Assert(d_tableau.isBasic(tmp));
+ RowIndex ri = d_tableau.basicToRowIndex(tmp);
+ d_linEq.stopTrackingRowIndex(ri);
d_tableau.removeBasicRow(tmp);
releaseVariable(tmp);
}
@@ -168,6 +170,12 @@ void SimplexDecisionProcedure::addToInfeasFunc(TimerStat& timer, ArithVar inf, A
adjustInfeasFunc(timer, inf, justE);
}
+void SimplexDecisionProcedure::removeFromInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e){
+ AVIntPairVec justE;
+ int opSgn = -d_errorSet.getSgn(e);
+ justE.push_back(make_pair(e, opSgn));
+ adjustInfeasFunc(timer, inf, justE);
+}
ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& timer, const ArithVarVec& set){
TimerStat::CodeTimer codeTimer(timer);
@@ -193,9 +201,10 @@ ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& time
DeltaRational newAssignment = d_linEq.computeRowValue(inf, false);
d_variables.setAssignment(inf, newAssignment);
- d_linEq.trackVariable(inf);
+ //d_linEq.trackVariable(inf);
+ d_linEq.trackRowIndex(d_tableau.basicToRowIndex(inf));
- Debug("Inf") << inf << " " << newAssignment << endl;
+ Debug("constructInfeasiblityFunction") << inf << " " << newAssignment << endl;
return inf;
}
@@ -226,7 +235,7 @@ void SimplexDecisionProcedure::addRowSgns(sgn_table& sgns, ArithVar basic, int n
}
}
-ArithVar SimplexDecisionProcedure::find_basic_outside(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m){
+ArithVar SimplexDecisionProcedure::find_basic_in_sgns(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m, bool inside){
pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
sgn_table::const_iterator i = sgns.find(p);
@@ -234,7 +243,7 @@ ArithVar SimplexDecisionProcedure::find_basic_outside(const sgn_table& sgns, Ari
const ArithVarVec& vec = (*i).second;
for(ArithVarVec::const_iterator viter = vec.begin(), vend = vec.end(); viter != vend; ++viter){
ArithVar curr = *viter;
- if(!m.isMember(curr)){
+ if(inside == m.isMember(curr)){
return curr;
}
}
diff --git a/src/theory/arith/simplex.h b/src/theory/arith/simplex.h
index bc47a128a..d646ca889 100644
--- a/src/theory/arith/simplex.h
+++ b/src/theory/arith/simplex.h
@@ -121,6 +121,7 @@ protected:
void tearDownInfeasiblityFunction(TimerStat& timer, ArithVar inf);
void adjustInfeasFunc(TimerStat& timer, ArithVar inf, const AVIntPairVec& focusChanges);
void addToInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e);
+ void removeFromInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e);
void shrinkInfeasFunc(TimerStat& timer, ArithVar inf, const ArithVarVec& dropped);
public:
@@ -197,7 +198,8 @@ protected:
void addSgn(sgn_table& sgns, ArithVar col, int sgn, ArithVar basic);
void addRowSgns(sgn_table& sgns, ArithVar basic, int norm);
- ArithVar find_basic_outside(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m);
+ ArithVar find_basic_in_sgns(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m, bool inside);
+
sgn_table::const_iterator find_sgns(const sgn_table& sgns, ArithVar col, int sgn);
};/* class SimplexDecisionProcedure */
diff --git a/src/theory/arith/simplex_update.h b/src/theory/arith/simplex_update.h
index 516586568..64aa193dd 100644
--- a/src/theory/arith/simplex_update.h
+++ b/src/theory/arith/simplex_update.h
@@ -318,7 +318,7 @@ private:
}
/**
- * Determines the appropraite WitnessImprovement for the update.
+ * Determines the appropriate WitnessImprovement for the update.
* useBlands breaks ties for degenerate pivots.
*
* This is safe if:
diff --git a/src/theory/arith/soi_simplex.cpp b/src/theory/arith/soi_simplex.cpp
index 7255d92ef..c0ee7ad20 100644
--- a/src/theory/arith/soi_simplex.cpp
+++ b/src/theory/arith/soi_simplex.cpp
@@ -22,6 +22,8 @@
#include "util/statistics_registry.h"
+#include <algorithm>
+
using namespace std;
namespace CVC4 {
@@ -237,7 +239,7 @@ UpdateInfo SumOfInfeasibilitiesSPD::selectUpdate(LinearEqualityModule::UpdatePre
Debug("soi::selectPrimalUpdate")
<< "selectPrimalUpdate " << instance << endl
<< d_soiVar << " " << d_tableau.basicRowLength(d_soiVar)
- << " " << d_linEq._countBounds(d_soiVar) << endl;
+ << " " << d_linEq.debugBasicAtBoundCount(d_soiVar) << endl;
typedef std::vector<Cand> CandVector;
CandVector candidates;
@@ -284,7 +286,6 @@ UpdateInfo SumOfInfeasibilitiesSPD::selectUpdate(LinearEqualityModule::UpdatePre
ArithVar curr = cand.d_nb;
const Rational& coeff = *cand.d_coeff;
-#warning "Who is using computeSafeUpdate?"
LinearEqualityModule::UpdatePreferenceFunction leavingPrefFunc = selectLeavingFunction(curr);
UpdateInfo currProposal = d_linEq.speculativeUpdate(curr, coeff, leavingPrefFunc);
@@ -349,7 +350,7 @@ void SumOfInfeasibilitiesSPD::debugPrintSignal(ArithVar updated) const{
int dir = !d_variables.assignmentIsConsistent(updated) ?
d_errorSet.getSgn(updated) : 0;
Debug("updateAndSignal") << " dir " << dir;
- Debug("updateAndSignal") << " _countBounds " << d_linEq._countBounds(updated) << endl;
+ Debug("updateAndSignal") << " debugBasicAtBoundCount " << d_linEq.debugBasicAtBoundCount(updated) << endl;
}
@@ -367,7 +368,7 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
ArithVar leaving = selected.leaving();
ss << "leaving " << leaving
<< " " << d_tableau.basicRowLength(leaving)
- << " " << d_linEq._countBounds(leaving)
+ << " " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
if(degenerate(w) && selected.describesPivot()){
@@ -376,7 +377,7 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
<< "degenerate " << leaving
<< ", atBounds " << d_linEq.basicsAtBounds(selected)
<< ", len " << d_tableau.basicRowLength(leaving)
- << ", bc " << d_linEq._countBounds(leaving)
+ << ", bc " << d_linEq.debugBasicAtBoundCount(leaving)
<< endl;
}
}
@@ -433,6 +434,192 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
adjustFocusAndError(selected, focusChanges);
}
+void SumOfInfeasibilitiesSPD::qeAddRange(uint32_t begin, uint32_t end){
+ Assert(!d_qeInSoi.empty());
+ for(uint32_t i = begin; i != end; ++i){
+ ArithVar v = d_qeConflict[i];
+ addToInfeasFunc(d_statistics.d_soiConflictMinimization, d_soiVar, v);
+ d_qeInSoi.add(v);
+ }
+}
+
+void SumOfInfeasibilitiesSPD::qeRemoveRange(uint32_t begin, uint32_t end){
+ for(uint32_t i = begin; i != end; ++i){
+ ArithVar v = d_qeConflict[i];
+ removeFromInfeasFunc(d_statistics.d_soiConflictMinimization, d_soiVar, v);
+ d_qeInSoi.remove(v);
+ }
+ Assert(!d_qeInSoi.empty());
+}
+
+void SumOfInfeasibilitiesSPD::qeSwapRange(uint32_t N, uint32_t r, uint32_t s){
+ for(uint32_t i = 0; i < N; ++i){
+ std::swap(d_qeConflict[r+i], d_qeConflict[s+i]);
+ }
+}
+
+/**
+ * Region notation:
+ * A region is either
+ * - A single element X@i with the name X at the position i
+ * - A sequence of indices X@[i,j) with the name X and the elements between i [inclusive] and j exclusive
+ * - A concatenation of regions R1 and R2, R1;R2
+ *
+ * Given the fixed assumptions C @ [0,cEnd) and a set of candidate minimizations U@[cEnd, uEnd)
+ * s.t. C \cup U is known to be in conflict ([0,uEnd) has a conflict), find a minimal
+ * subset of U, Delta, s.t. C \cup Delta is in conflict.
+ *
+ * Pre:
+ * [0, uEnd) is a set and is in conflict.
+ * uEnd <= assumptions.size()
+ * [0, cEnd) is in d_inSoi.
+ *
+ * Invariants: [0,cEnd) is never modified
+ *
+ * Post:
+ * [0, cEnd); [cEnd, deltaEnd) is in conflict
+ * [0, deltaEnd) is a set
+ * [0, deltaEnd) is in d_inSoi
+ */
+uint32_t SumOfInfeasibilitiesSPD::quickExplainRec(uint32_t cEnd, uint32_t uEnd){
+ Assert(cEnd <= uEnd);
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+
+ const Tableau::Entry* spoiler = NULL;
+
+ if(d_soiVar != ARITHVAR_SENTINEL && d_linEq.selectSlackEntry(d_soiVar, false) == NULL){
+ // already in conflict
+ return cEnd;
+ }
+
+ Assert(cEnd < uEnd);
+
+ // Phase 1 : Construct the conflict greedily
+
+ for(uint32_t i = cEnd; i < uEnd; ++i){
+ d_qeInUAndNotInSoi.add(d_qeConflict[i]);
+ }
+ if(d_soiVar == ARITHVAR_SENTINEL){ // special case for d_soiVar being empty
+ ArithVar first = d_qeConflict[cEnd];
+ d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization, first);
+ d_qeInSoi.add(first);
+ d_qeInUAndNotInSoi.remove(first);
+ d_qeGreedyOrder.push_back(first);
+ }
+ while((spoiler = d_linEq.selectSlackEntry(d_soiVar, false)) != NULL){
+ Assert(!d_qeInUAndNotInSoi.empty());
+
+ ArithVar nb = spoiler->getColVar();
+ int oppositeSgn = -(spoiler->getCoefficient().sgn());
+ Assert(oppositeSgn != 0);
+
+ ArithVar basicWithOp = find_basic_in_sgns(d_qeSgns, nb, oppositeSgn, d_qeInUAndNotInSoi, true);
+ Assert(basicWithOp != ARITHVAR_SENTINEL);
+
+ addToInfeasFunc(d_statistics.d_soiConflictMinimization, d_soiVar, basicWithOp);
+ d_qeInSoi.add(basicWithOp);
+ d_qeInUAndNotInSoi.remove(basicWithOp);
+ d_qeGreedyOrder.push_back(basicWithOp);
+ }
+ Assert(spoiler == NULL);
+
+ // Compact the set u
+ uint32_t newEnd = cEnd + d_qeGreedyOrder.size();
+ std::copy(d_qeGreedyOrder.begin(), d_qeGreedyOrder.end(), d_qeConflict.begin()+cEnd);
+
+ d_qeInUAndNotInSoi.purge();
+ d_qeGreedyOrder.clear();
+
+ // Phase 2 : Recursively determine the minimal set of rows
+
+ uint32_t xPos = cEnd;
+ std::swap(d_qeGreedyOrder[xPos], d_qeGreedyOrder[newEnd - 1]);
+ uint32_t uBegin = xPos + 1;
+ uint32_t split = (newEnd - uBegin)/2 + uBegin;
+
+ //assumptions : C @ [0, cEnd); X @ xPos; U1 @ [u1Begin, split); U2 @ [split, newEnd)
+ // [0, newEnd) == d_inSoi
+
+ uint32_t compactU2;
+ if(split == newEnd){ // U2 is empty
+ compactU2 = newEnd;
+ }else{
+ // Remove U2 from Soi
+ qeRemoveRange(split, newEnd);
+ // [0, split) == d_inSoi
+
+ // pre assumptions: C + X + U1 @ [0,split); U2 [split, newEnd)
+ compactU2 = quickExplainRec(split, newEnd);
+ // post:
+ // assumptions: C + X + U1 @ [0, split); delta2 @ [split - compactU2)
+ // d_inSoi = [0, compactU2)
+ }
+ uint32_t deltaSize = compactU2 - split;
+ qeSwapRange(deltaSize, uBegin, split);
+ uint32_t d2End = uBegin+deltaSize;
+ // assumptions : C @ [0, cEnd); X @ xPos; delta2 @ [uBegin, d2End); U1 @ [d2End, compactU2)
+ // d_inSoi == [0, compactU2)
+
+ uint32_t d1End;
+ if(d2End == compactU2){ // U1 is empty
+ d1End = d2End;
+ }else{
+ qeRemoveRange(d2End, compactU2);
+
+ //pre assumptions : C + X + delta2 @ [0, d2End); U1 @ [d2End, compactU2);
+ d1End = quickExplainRec(d2End, compactU2);
+ //post:
+ // assumptions : C + X + delta2 @ [0, d2End); delta1 @ [d2End, d1End);
+ // d_inSoi = [0, d1End)
+ }
+ //After both:
+ // d_inSoi == [0, d1End), C @ [0, cEnd); X + delta2 + delta 1 @ [xPos, d1End);
+
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+ return d1End;
+}
+
+void SumOfInfeasibilitiesSPD::quickExplain(){
+ Assert(d_qeInSoi.empty());
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+ Assert(d_soiVar == ARITHVAR_SENTINEL);
+ Assert(d_qeSgns.empty());
+
+ d_qeConflict.clear();
+ d_errorSet.pushFocusInto(d_qeConflict);
+
+ //cout << d_qeConflict.size() << " ";
+ uint32_t size = d_qeConflict.size();
+
+ if(size > 2){
+ for(ErrorSet::focus_iterator iter = d_errorSet.focusBegin(), end = d_errorSet.focusEnd(); iter != end; ++iter){
+ ArithVar e = *iter;
+ addRowSgns(d_qeSgns, e, d_errorSet.getSgn(e));
+ }
+ uint32_t end = quickExplainRec(0u, size);
+ Assert(end <= d_qeConflict.size());
+ Assert(d_soiVar != ARITHVAR_SENTINEL);
+ Assert(!d_qeInSoi.empty());
+
+ d_qeConflict.resize(end);
+ tearDownInfeasiblityFunction(d_statistics.d_soiConflictMinimization, d_soiVar);
+ d_soiVar = ARITHVAR_SENTINEL;
+ d_qeInSoi.purge();
+ d_qeSgns.clear();
+ }
+
+ //cout << d_qeConflict.size() << endl;
+
+ Assert(d_qeInSoi.empty());
+ Assert(d_qeInUAndNotInSoi.empty());
+ Assert(d_qeGreedyOrder.empty());
+ Assert(d_soiVar == ARITHVAR_SENTINEL);
+ Assert(d_qeSgns.empty());
+}
+
unsigned SumOfInfeasibilitiesSPD::trySet(const ArithVarVec& set){
Assert(d_soiVar == ARITHVAR_SENTINEL);
bool success = false;
@@ -446,30 +633,6 @@ unsigned SumOfInfeasibilitiesSPD::trySet(const ArithVarVec& set){
return success ? set.size() : std::numeric_limits<int>::max();
}
-unsigned SumOfInfeasibilitiesSPD::tryAllSubsets(const ArithVarVec& set, unsigned depth, ArithVarVec& tmp) {
- if(depth < set.size()){
- unsigned resWithout = tryAllSubsets(set, depth+1, tmp);
- if(resWithout == tmp.size() && resWithout < set.size()){
- for(unsigned i = 0; i < tmp.size(); ++i){
- cout << tmp[i] << " ";
- }
- cout << endl;
- }
- tmp.push_back(set[depth]);
- unsigned resWith = tryAllSubsets(set, depth+1, tmp);
- if(resWith == tmp.size() && resWith < set.size()){
- for(unsigned i = 0; i < tmp.size(); ++i){
- cout << tmp[i] << " ";
- }
- cout << endl;
- }
- tmp.pop_back();
- return std::min(resWith, resWithout);
- }else{
- return trySet(tmp);
- }
-}
-
std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
std::vector< ArithVarVec > subsets;
Assert(d_soiVar == ARITHVAR_SENTINEL);
@@ -547,8 +710,6 @@ std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
underConstruction.push_back(v);
d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization, v);
- bool uniqueChoices = true;
-
//cout << "trying " << v << endl;
const Tableau::Entry* spoiler = NULL;
@@ -559,7 +720,7 @@ std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
//cout << "looking for " << nb << " " << oppositeSgn << endl;
- ArithVar basicWithOp = find_basic_outside(sgns, nb, oppositeSgn, hasParticipated);
+ ArithVar basicWithOp = find_basic_in_sgns(sgns, nb, oppositeSgn, hasParticipated, false);
if(basicWithOp == ARITHVAR_SENTINEL){
//cout << "search did not work for " << nb << endl;
@@ -648,17 +809,26 @@ WitnessImprovement SumOfInfeasibilitiesSPD::SOIConflict(){
tearDownInfeasiblityFunction(d_statistics.d_soiConflictMinimization, d_soiVar);
d_soiVar = ARITHVAR_SENTINEL;
- vector<ArithVarVec> subsets = greedyConflictSubsets();
- Assert( d_soiVar == ARITHVAR_SENTINEL);
- Assert(!subsets.empty());
- for(vector<ArithVarVec>::const_iterator i = subsets.begin(), end = subsets.end(); i != end; ++i){
- const ArithVarVec& subset = *i;
- Node conflict = generateSOIConflict(subset);
+ if(options::soiQuickExplain()){
+ quickExplain();
+ Node conflict = generateSOIConflict(d_qeConflict);
//cout << conflict << endl;
-
- //reportConflict(conf); do not do this. We need a custom explanations!
d_conflictChannel(conflict);
+ }else{
+
+ vector<ArithVarVec> subsets = greedyConflictSubsets();
+ Assert( d_soiVar == ARITHVAR_SENTINEL);
+
+ Assert(!subsets.empty());
+ for(vector<ArithVarVec>::const_iterator i = subsets.begin(), end = subsets.end(); i != end; ++i){
+ const ArithVarVec& subset = *i;
+ Node conflict = generateSOIConflict(subset);
+ //cout << conflict << endl;
+
+ //reportConflict(conf); do not do this. We need a custom explanations!
+ d_conflictChannel(conflict);
+ }
}
Assert( d_soiVar == ARITHVAR_SENTINEL);
d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization);
@@ -703,7 +873,7 @@ WitnessImprovement SumOfInfeasibilitiesSPD::soiRound() {
}
bool SumOfInfeasibilitiesSPD::debugSOI(WitnessImprovement w, ostream& out, int instance) const{
-#warning "Redo SOI"
+//#warning "Redo SOI"
return true;
// out << "DLV("<<instance<<") ";
// switch(w){
diff --git a/src/theory/arith/soi_simplex.h b/src/theory/arith/soi_simplex.h
index 006839a55..de565df64 100644
--- a/src/theory/arith/soi_simplex.h
+++ b/src/theory/arith/soi_simplex.h
@@ -195,6 +195,19 @@ private:
IntStat& conflictStat = d_statistics.d_initialConflicts;
return standardProcessSignals(timer, conflictStat);
}
+
+ void quickExplain();
+ DenseSet d_qeInSoi;
+ DenseSet d_qeInUAndNotInSoi;
+ ArithVarVec d_qeConflict;
+ ArithVarVec d_qeGreedyOrder;
+ sgn_table d_qeSgns;
+
+ uint32_t quickExplainRec(uint32_t cEnd, uint32_t uEnd);
+ void qeAddRange(uint32_t begin, uint32_t end);
+ void qeRemoveRange(uint32_t begin, uint32_t end);
+ void qeSwapRange(uint32_t N, uint32_t r, uint32_t s);
+
unsigned trySet(const ArithVarVec& set);
unsigned tryAllSubsets(const ArithVarVec& set, unsigned depth, ArithVarVec& tmp);
diff --git a/src/theory/arith/tableau.cpp b/src/theory/arith/tableau.cpp
index c54b0857a..9d06fadc4 100644
--- a/src/theory/arith/tableau.cpp
+++ b/src/theory/arith/tableau.cpp
@@ -75,7 +75,7 @@ void Tableau::rowPivot(ArithVar basicOld, ArithVar basicNew, CoefficientChangeCa
d_basic2RowIndex.set(basicNew, rid);
d_rowIndex2basic.set(rid, basicNew);
- cb.swap(basicOld, basicNew, a_rs_sgn);
+ cb.multiplyRow(rid, -a_rs_sgn);
}
diff --git a/src/theory/arith/tableau.h b/src/theory/arith/tableau.h
index 8b6ef1df6..deed7e7be 100644
--- a/src/theory/arith/tableau.h
+++ b/src/theory/arith/tableau.h
@@ -72,8 +72,12 @@ public:
return getColumn(x).begin();
}
+ RowIterator ridRowIterator(RowIndex rid) const {
+ return getRow(rid).begin();
+ }
+
RowIterator basicRowIterator(ArithVar basic) const {
- return getRow(basicToRowIndex(basic)).begin();
+ return ridRowIterator(basicToRowIndex(basic));
}
const Entry& basicFindEntry(ArithVar basic, ArithVar col) const {
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index c0442da90..6c7f622ec 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -47,6 +47,7 @@ void TheoryArith::addSharedTerm(TNode n){
}
Node TheoryArith::ppRewrite(TNode atom) {
+ CodeTimer timer(d_ppRewriteTimer);
return d_internal->ppRewrite(atom);
}
@@ -86,6 +87,10 @@ EqualityStatus TheoryArith::getEqualityStatus(TNode a, TNode b) {
return d_internal->getEqualityStatus(a,b);
}
+Node TheoryArith::getModelValue(TNode var) {
+ return d_internal->getModelValue( var );
+}
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index 10c79b293..451f1e8ff 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -42,6 +42,7 @@ private:
TheoryArithPrivate* d_internal;
+ KEEP_STATISTIC(TimerStat, d_ppRewriteTimer, "theory::arith::ppRewriteTimer");
public:
TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
@@ -73,6 +74,8 @@ public:
EqualityStatus getEqualityStatus(TNode a, TNode b);
void addSharedTerm(TNode n);
+
+ Node getModelValue(TNode var);
};/* class TheoryArith */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index 263f9536b..9d13dccb7 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -67,6 +67,8 @@
#include "theory/arith/options.h"
+#include "theory/quantifiers/bounded_integers.h"
+
#include <stdint.h>
#include <vector>
@@ -83,12 +85,13 @@ namespace arith {
TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
d_containing(containing),
d_nlIncomplete( false),
- d_boundTracking(),
+ d_rowTracking(),
d_constraintDatabase(c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this)),
d_qflraStatus(Result::SAT_UNKNOWN),
d_unknownsInARow(0),
d_hasDoneWorkSinceCut(false),
d_learner(u),
+ d_quantEngine(qe),
d_assertionsThatDoNotMatchTheirLiterals(c),
d_nextIntegerCheckVar(0),
d_constantIntegerVariables(c),
@@ -96,9 +99,9 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context
d_currentPropagationList(),
d_learnedBounds(c),
d_partialModel(c, DeltaComputeCallback(*this)),
- d_errorSet(d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(&d_boundTracking)),
+ d_errorSet(d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)),
d_tableau(),
- d_linEq(d_partialModel, d_tableau, d_boundTracking, BasicVarModelUpdateCallBack(*this)),
+ d_linEq(d_partialModel, d_tableau, d_rowTracking, BasicVarModelUpdateCallBack(*this)),
d_diosolver(c),
d_restartsCounter(0),
d_tableauSizeHasBeenModified(false),
@@ -107,15 +110,19 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context
d_conflicts(c),
d_congruenceManager(c, d_constraintDatabase, SetupLiteralCallBack(*this), d_partialModel, RaiseConflict(*this)),
d_dualSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
- d_pureUpdate(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_fcSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_soiSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
+ d_attemptSolSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_DELTA_ZERO(0),
d_fullCheckCounter(0),
d_cutCount(c, 0),
d_cutInContext(c),
+ d_likelyIntegerInfeasible(c, false),
+ d_guessedCoeffSet(c, false),
+ d_guessedCoeffs(),
d_statistics()
{
+ srand(79);
}
TheoryArithPrivate::~TheoryArithPrivate(){ }
@@ -489,9 +496,7 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
}else if(!lb->negationHasProof()){
Constraint negLb = lb->getNegation();
negLb->impliedBy(constraint, diseq);
- //if(!negLb->canBePropagated()){
d_learnedBounds.push_back(negLb);
- //}//otherwise let this be propagated/asserted later
}
}
}
@@ -732,19 +737,155 @@ void TheoryArithPrivate::addSharedTerm(TNode n){
}
}
+Node TheoryArithPrivate::getModelValue(TNode term) {
+ try{
+ DeltaRational drv = getDeltaValue(term);
+ const Rational& delta = d_partialModel.getDelta();
+ Rational qmodel = drv.substituteDelta( delta );
+ return mkRationalNode( qmodel );
+ } catch (DeltaRationalException& dr) {
+ return Node::null();
+ } catch (ModelException& me) {
+ return Node::null();
+ }
+}
+
+namespace attr {
+ struct ToIntegerTag { };
+ struct LinearIntDivTag { };
+}/* CVC4::theory::arith::attr namespace */
+
+/**
+ * This attribute maps the child of a to_int / is_int to the
+ * corresponding integer skolem.
+ */
+typedef expr::Attribute<attr::ToIntegerTag, Node> ToIntegerAttr;
+
+/**
+ * This attribute maps division-by-constant-k terms to a variable
+ * used to eliminate them.
+ */
+typedef expr::Attribute<attr::LinearIntDivTag, Node> LinearIntDivAttr;
+
+Node TheoryArithPrivate::ppRewriteTerms(TNode n) {
+ if(Theory::theoryOf(n) != THEORY_ARITH) {
+ return n;
+ }
+
+ NodeManager* nm = NodeManager::currentNM();
+
+ switch(Kind k = n.getKind()) {
+
+ case kind::TO_INTEGER:
+ case kind::IS_INTEGER: {
+ Node intVar;
+ if(!n[0].getAttribute(ToIntegerAttr(), intVar)) {
+ intVar = nm->mkSkolem("toInt", nm->integerType(), "a conversion of a Real term to its Integer part");
+ n[0].setAttribute(ToIntegerAttr(), intVar);
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LT, nm->mkNode(kind::MINUS, n[0], nm->mkConst(Rational(1))), intVar), nm->mkNode(kind::LEQ, intVar, n[0])));
+ }
+ if(n.getKind() == kind::TO_INTEGER) {
+ Node node = intVar;
+ return node;
+ } else {
+ Node node = nm->mkNode(kind::EQUAL, n[0], intVar);
+ return node;
+ }
+ Unreachable();
+ }
+
+ case kind::INTS_DIVISION:
+ case kind::INTS_DIVISION_TOTAL: {
+ if(!options::rewriteDivk()) {
+ return n;
+ }
+ Node num = Rewriter::rewrite(n[0]);
+ Node den = Rewriter::rewrite(n[1]);
+ if(den.isConst()) {
+ const Rational& rat = den.getConst<Rational>();
+ Assert(!num.isConst());
+ if(rat != 0) {
+ Node intVar;
+ Node rw = nm->mkNode(k, num, den);
+ if(!rw.getAttribute(LinearIntDivAttr(), intVar)) {
+ intVar = nm->mkSkolem("linearIntDiv", nm->integerType(), "the result of an intdiv-by-k term");
+ rw.setAttribute(LinearIntDivAttr(), intVar);
+ if(rat > 0) {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(1)))))));
+ } else {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(-1)))))));
+ }
+ }
+ return intVar;
+ }
+ }
+ break;
+ }
+
+ case kind::INTS_MODULUS:
+ case kind::INTS_MODULUS_TOTAL: {
+ if(!options::rewriteDivk()) {
+ return n;
+ }
+ Node num = Rewriter::rewrite(n[0]);
+ Node den = Rewriter::rewrite(n[1]);
+ if(den.isConst()) {
+ const Rational& rat = den.getConst<Rational>();
+ Assert(!num.isConst());
+ if(rat != 0) {
+ Node intVar;
+ Node rw = nm->mkNode(k, num, den);
+ if(!rw.getAttribute(LinearIntDivAttr(), intVar)) {
+ intVar = nm->mkSkolem("linearIntDiv", nm->integerType(), "the result of an intdiv-by-k term");
+ rw.setAttribute(LinearIntDivAttr(), intVar);
+ if(rat > 0) {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(1)))))));
+ } else {
+ d_containing.d_out->lemma(nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num), nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(-1)))))));
+ }
+ }
+ Node node = nm->mkNode(kind::MINUS, num, nm->mkNode(kind::MULT, den, intVar));
+ return node;
+ }
+ }
+ break;
+ }
+
+ default:
+ ;
+ }
+
+ for(TNode::const_iterator i = n.begin(); i != n.end(); ++i) {
+ Node rewritten = ppRewriteTerms(*i);
+ if(rewritten != *i) {
+ NodeBuilder<> b(n.getKind());
+ b.append(n.begin(), i);
+ b << rewritten;
+ for(++i; i != n.end(); ++i) {
+ b << ppRewriteTerms(*i);
+ }
+ rewritten = b;
+ return rewritten;
+ }
+ }
+
+ return n;
+}
+
Node TheoryArithPrivate::ppRewrite(TNode atom) {
Debug("arith::preprocess") << "arith::preprocess() : " << atom << endl;
-
if (atom.getKind() == kind::EQUAL && options::arithRewriteEq()) {
Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
+ leq = ppRewriteTerms(leq);
+ geq = ppRewriteTerms(geq);
Node rewritten = Rewriter::rewrite(leq.andNode(geq));
Debug("arith::preprocess") << "arith::preprocess() : returning "
<< rewritten << endl;
return rewritten;
} else {
- return atom;
+ return ppRewriteTerms(atom);
}
}
@@ -897,7 +1038,7 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){
// vl is the product of at least 2 variables
// vl : (* v1 v2 ...)
if(getLogicInfo().isLinear()){
- throw LogicException("Non-linear term was asserted to arithmetic in a linear logic.");
+ throw LogicException("A non-linear fact was asserted to arithmetic in a linear logic.");
}
setIncomplete();
@@ -934,7 +1075,7 @@ void TheoryArithPrivate::setupDivLike(const Variable& v){
Assert(v.isDivLike());
if(getLogicInfo().isLinear()){
- throw LogicException("Non-linear term was asserted to arithmetic in a linear logic.");
+ throw LogicException("A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic;\nif you only use division (or modulus) by a constant value, or if you only use the divisibility-by-k predicate, try using the --rewrite-divk option.");
}
Node vnode = v.getNode();
@@ -1100,7 +1241,7 @@ void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
ArithVar varSlack = requestArithVar(polyNode, true);
d_tableau.addRow(varSlack, coefficients, variables);
setupBasicValue(varSlack);
- d_linEq.trackVariable(varSlack);
+ d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
//Add differences to the difference manager
Polynomial::iterator i = poly.begin(), end = poly.end();
@@ -1156,16 +1297,22 @@ void TheoryArithPrivate::setupAtom(TNode atom) {
void TheoryArithPrivate::preRegisterTerm(TNode n) {
Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
- if(isRelationOperator(n.getKind())){
- if(!isSetup(n)){
- setupAtom(n);
+ try {
+ if(isRelationOperator(n.getKind())){
+ if(!isSetup(n)){
+ setupAtom(n);
+ }
+ Constraint c = d_constraintDatabase.lookup(n);
+ Assert(c != NullConstraint);
+
+ Debug("arith::preregister") << "setup constraint" << c << endl;
+ Assert(!c->canBePropagated());
+ c->setPreregistered();
}
- Constraint c = d_constraintDatabase.lookup(n);
- Assert(c != NullConstraint);
-
- Debug("arith::preregister") << "setup constraint" << c << endl;
- Assert(!c->canBePropagated());
- c->setPreregistered();
+ } catch(LogicException& le) {
+ std::stringstream ss;
+ ss << le.getMessage() << endl << "The fact in question: " << n << endl;
+ throw LogicException(ss.str());
}
Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl;
@@ -1176,82 +1323,33 @@ void TheoryArithPrivate::releaseArithVar(ArithVar v){
d_constraintDatabase.removeVariable(v);
d_partialModel.releaseArithVar(v);
- d_linEq.maybeRemoveTracking(v);
}
ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
//TODO : The VarList trick is good enough?
Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS);
if(getLogicInfo().isLinear() && Variable::isDivMember(x)){
- throw LogicException("Non-linear term was asserted to arithmetic in a linear logic.");
+ stringstream ss;
+ ss << "A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic: " << x << endl
+ << "if you only use division (or modulus) by a constant value, or if you only use the divisibility-by-k predicate, try using the --rewrite-divk option.";
+ throw LogicException(ss.str());
}
Assert(!d_partialModel.hasArithVar(x));
Assert(x.getType().isReal()); // real or integer
- // ArithVar varX = d_variables.size();
- // d_variables.push_back(Node(x));
-
ArithVar max = d_partialModel.getNumberOfVariables();
ArithVar varX = d_partialModel.allocate(x, slack);
bool reclaim = max >= d_partialModel.getNumberOfVariables();;
- if(reclaim){
- // varX = d_pool.back();
- // d_pool.pop_back();
-
- // d_partialModel.setAssignment(varX, d_DELTA_ZERO, d_DELTA_ZERO);
- }else{
- // varX = d_numberOfVariables;
- // ++d_numberOfVariables;
-
- // d_slackVars.push_back(true);
- // d_variableTypes.push_back(ATReal);
-
+ if(!reclaim){
d_dualSimplex.increaseMax();
d_tableau.increaseSize();
d_tableauSizeHasBeenModified = true;
-
- //d_partialModel.initialize(varX, d_DELTA_ZERO);
}
-
- // ArithType type;
- // if(slack){
- // //The type computation is not quite accurate for Rationals that are integral.
- // //We'll use the isIntegral check from the polynomial package instead.
- // Polynomial p = Polynomial::parsePolynomial(x);
- // type = p.isIntegral() ? ATInteger : ATReal;
- // }else{
- // type = nodeToArithType(x);
- // }
- // d_variableTypes[varX] = type;
- // d_slackVars[varX] = slack;
-
d_constraintDatabase.addVariable(varX);
- //d_partialModel.setArithVar(x,varX);
-
- // Debug("integers") << "isInteger[[" << x << "]]: " << x.getType().isInteger() << endl;
-
- // if(slack){
- // //The type computation is not quite accurate for Rationals that are integral.
- // //We'll use the isIntegral check from the polynomial package instead.
- // Polynomial p = Polynomial::parsePolynomial(x);
- // d_variableTypes.push_back(p.isIntegral() ? ATInteger : ATReal);
- // }else{
- // d_variableTypes.push_back(nodeToArithType(x));
- // }
-
- // d_slackVars.push_back(slack);
-
- // d_simplex.increaseMax();
-
- // d_tableau.increaseSize();
- // d_tableauSizeHasBeenModified = true;
-
- // d_constraintDatabase.addVariable(varX);
-
Debug("arith::arithvar") << x << " |-> " << varX << endl;
Assert(!d_partialModel.hasUpperBound(varX));
@@ -1423,6 +1521,10 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
Assert(!done());
TNode assertion = get();
+ if( options::finiteModelFind() && d_quantEngine && d_quantEngine->getBoundedIntegers() ){
+ d_quantEngine->getBoundedIntegers()->assertNode(assertion);
+ }
+
Kind simpleKind = Comparison::comparisonKind(assertion);
Constraint constraint = d_constraintDatabase.lookup(assertion);
if(constraint == NullConstraint){
@@ -1454,20 +1556,6 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
}
}
- // Kind simpleKind = Comparison::comparisonKind(assertion);
- // Assert(simpleKind != UNDEFINED_KIND);
- // Assert(constraint != NullConstraint ||
- // simpleKind == EQUAL ||
- // simpleKind == DISTINCT );
- // if(simpleKind == EQUAL || simpleKind == DISTINCT){
- // Node eq = (simpleKind == DISTINCT) ? assertion[0] : assertion;
-
- // if(!isSetup(eq)){
- // //The previous code was equivalent to:
- // setupAtom(eq);
- // constraint = d_constraintDatabase.lookup(assertion);
- // }
- // }
Assert(constraint != NullConstraint);
if(constraint->negationHasProof()){
@@ -1609,9 +1697,9 @@ void TheoryArithPrivate::branchVector(const std::vector<ArithVar>& lemmas){
bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
Assert(d_qflraStatus != Result::SAT);
- d_partialModel.stopQueueingAtBoundQueue();
+ d_partialModel.stopQueueingBoundCounts();
UpdateTrackingCallback utcb(&d_linEq);
- d_partialModel.processAtBoundQueue(utcb);
+ d_partialModel.processBoundsQueue(utcb);
d_linEq.startTrackingBoundCounts();
bool noPivotLimit = Theory::fullEffort(effortLevel) ||
@@ -1641,13 +1729,23 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
static const int32_t relaxationLimit = 10000;
static const int32_t mipLimit = 200000;
+ //cout << "start" << endl;
d_qflraStatus = simplex.findModel(false);
+ //cout << "end" << endl;
if(d_qflraStatus == Result::SAT_UNKNOWN ||
- (d_qflraStatus == Result::SAT && !hasIntegerModel())){
+ (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel);
approxSolver->setPivotLimit(relaxationLimit);
+ if(!d_guessedCoeffSet){
+ d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
+ d_guessedCoeffSet = true;
+ }
+ if(!d_guessedCoeffs.empty()){
+ approxSolver->setOptCoeffs(d_guessedCoeffs);
+ }
+
ApproximateSimplex::ApproxResult relaxRes, mipRes;
ApproximateSimplex::Solution relaxSolution, mipSolution;
relaxRes = approxSolver->solveRelaxation();
@@ -1655,30 +1753,37 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
case ApproximateSimplex::ApproxSat:
{
relaxSolution = approxSolver->extractRelaxation();
- approxSolver->setPivotLimit(mipLimit);
- mipRes = approxSolver->solveMIP();
- d_errorSet.reduceToSignals();
- if(mipRes == ApproximateSimplex::ApproxSat){
- mipSolution = approxSolver->extractMIP();
- ApproximateSimplex::applySolution(d_linEq, mipSolution);
+
+ if(d_likelyIntegerInfeasible){
+ d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
}else{
- ApproximateSimplex::applySolution(d_linEq, relaxSolution);
- // if(d_qflraStatus != UNSAT){
- // d_likelyIntegerUnsat = true;
- // }
+ approxSolver->setPivotLimit(mipLimit);
+ mipRes = approxSolver->solveMIP();
+ d_errorSet.reduceToSignals();
+ //Message() << "here" << endl;
+ if(mipRes == ApproximateSimplex::ApproxSat){
+ mipSolution = approxSolver->extractMIP();
+ d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
+ }else{
+ if(mipRes == ApproximateSimplex::ApproxUnsat){
+ d_likelyIntegerInfeasible = true;
+ }
+ d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+ }
}
options::arithStandardCheckVarOrderPivots.set(pass2Limit);
- d_qflraStatus = simplex.findModel(false);
+ if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+ //Message() << "done" << endl;
}
break;
case ApproximateSimplex::ApproxUnsat:
{
ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
- d_errorSet.reduceToSignals();
- ApproximateSimplex::applySolution(d_linEq, sol);
- options::arithStandardCheckVarOrderPivots.set(100);
- d_qflraStatus = simplex.findModel(false);
+ d_qflraStatus = d_attemptSolSimplex.attempt(sol);
+ options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+
+ if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
}
break;
default:
@@ -1688,11 +1793,14 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
}
if(d_qflraStatus == Result::SAT_UNKNOWN){
+ //Message() << "got sat unknown" << endl;
vector<ArithVar> toCut = cutAllBounded();
if(toCut.size() > 0){
branchVector(toCut);
emmittedConflictOrSplit = true;
}else{
+ //Message() << "splitting" << endl;
+
d_qflraStatus = simplex.findModel(noPivotLimit);
}
}
@@ -1701,7 +1809,7 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
// TODO Save zeroes with no conflicts
d_linEq.stopTrackingBoundCounts();
- d_partialModel.startQueueingAtBoundQueue();
+ d_partialModel.startQueueingBoundCounts();
return emmittedConflictOrSplit;
}
@@ -1765,7 +1873,7 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(Debug.isOn("arith::print_assertions")) {
- debugPrintAssertions();
+ debugPrintAssertions(Debug("arith::print_assertions"));
}
bool emmittedConflictOrSplit = false;
@@ -1911,7 +2019,6 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
emmittedConflictOrSplit = splitDisequalities();
}
- emmittedConflictOrSplit = false;
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
Node possibleConflict = Node::null();
@@ -1967,7 +2074,9 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
- if(Debug.isOn("arith::print_model")) { debugPrintModel(); }
+ if(Debug.isOn("arith::print_model")) {
+ debugPrintModel(Debug("arith::print_model"));
+ }
Debug("arith") << "TheoryArithPrivate::check end" << std::endl;
}
@@ -2088,37 +2197,38 @@ bool TheoryArithPrivate::splitDisequalities(){
* Should be guarded by at least Debug.isOn("arith::print_assertions").
* Prints to Debug("arith::print_assertions")
*/
-void TheoryArithPrivate::debugPrintAssertions() {
- Debug("arith::print_assertions") << "Assertions:" << endl;
+void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
+ out << "Assertions:" << endl;
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar i = *vi;
if (d_partialModel.hasLowerBound(i)) {
Constraint lConstr = d_partialModel.getLowerBoundConstraint(i);
- Debug("arith::print_assertions") << lConstr << endl;
+ out << lConstr << endl;
}
if (d_partialModel.hasUpperBound(i)) {
Constraint uConstr = d_partialModel.getUpperBoundConstraint(i);
- Debug("arith::print_assertions") << uConstr << endl;
+ out << uConstr << endl;
}
}
context::CDQueue<Constraint>::const_iterator it = d_diseqQueue.begin();
context::CDQueue<Constraint>::const_iterator it_end = d_diseqQueue.end();
for(; it != it_end; ++ it) {
- Debug("arith::print_assertions") << *it << endl;
+ out << *it << endl;
}
}
-void TheoryArithPrivate::debugPrintModel(){
- Debug("arith::print_model") << "Model:" << endl;
+void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{
+ out << "Model:" << endl;
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar i = *vi;
if(d_partialModel.hasNode(i)){
- Debug("arith::print_model") << d_partialModel.asNode(i) << " : " <<
+ out << d_partialModel.asNode(i) << " : " <<
d_partialModel.getAssignment(i);
- if(d_tableau.isBasic(i))
- Debug("arith::print_model") << " (basic)";
- Debug("arith::print_model") << endl;
+ if(d_tableau.isBasic(i)){
+ out << " (basic)";
+ }
+ out << endl;
}
}
}
@@ -2161,7 +2271,11 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
(options::arithPropagationMode() == BOUND_INFERENCE_PROP ||
options::arithPropagationMode() == BOTH_PROP)
&& hasAnyUpdates()){
- propagateCandidates();
+ if(options::newProp()){
+ propagateCandidatesNew();
+ }else{
+ propagateCandidates();
+ }
}else{
clearUpdates();
}
@@ -2432,37 +2546,6 @@ void TheoryArithPrivate::notifyRestart(){
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
++d_restartsCounter;
-#warning "removing restart"
- // return;
-
- // uint32_t currSize = d_tableau.size();
- // uint32_t copySize = d_smallTableauCopy.size();
-
- // Debug("arith::reset") << "resetting" << d_restartsCounter << endl;
- // Debug("arith::reset") << "curr " << currSize << " copy " << copySize << endl;
- // Debug("arith::reset") << "tableauSizeHasBeenModified " << d_tableauSizeHasBeenModified << endl;
-
- // if(d_tableauSizeHasBeenModified){
- // Debug("arith::reset") << "row has been added must copy " << d_restartsCounter << endl;
- // d_smallTableauCopy = d_tableau;
- // d_tableauSizeHasBeenModified = false;
- // }else if( d_restartsCounter >= RESET_START){
- // if(copySize >= currSize * 1.1 ){
- // Debug("arith::reset") << "size has shrunk " << d_restartsCounter << endl;
- // ++d_statistics.d_smallerSetToCurr;
- // d_smallTableauCopy = d_tableau;
- // }else if(d_tableauResetDensity * copySize <= currSize){
- // d_errorSet.popAllSignals();
- // if(safeToReset()){
- // Debug("arith::reset") << "resetting " << d_restartsCounter << endl;
- // ++d_statistics.d_currSetToSmaller;
- // d_tableau = d_smallTableauCopy;
- // }else{
- // Debug("arith::reset") << "not safe to reset at the moment " << d_restartsCounter << endl;
- // }
- // }
- // }
- // Assert(unenqueuedVariablesAreConsistent());
}
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
@@ -2478,6 +2561,14 @@ bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
}
Warning() << endl;
result = false;
+ }else if(d_partialModel.isInteger(var) && !d_partialModel.integralAssignment(var)){
+ d_partialModel.printModel(var);
+ Warning() << s << ":" << "Assignment is not integer for integer variable " << var << d_partialModel.asNode(var);
+ if(d_tableau.isBasic(var)){
+ Warning() << " (basic)";
+ }
+ Warning() << endl;
+ result = false;
}
}
return result;
@@ -2570,9 +2661,8 @@ EqualityStatus TheoryArithPrivate::getEqualityStatus(TNode a, TNode b) {
bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound){
++d_statistics.d_boundComputations;
- DeltaRational bound = upperBound ?
- d_linEq.computeUpperBound(basic):
- d_linEq.computeLowerBound(basic);
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ DeltaRational bound = d_linEq.computeRowBound(ridx, upperBound, basic);
if((upperBound && d_partialModel.strictlyLessThanUpperBound(basic, bound)) ||
(!upperBound && d_partialModel.strictlyGreaterThanLowerBound(basic, bound))){
@@ -2620,28 +2710,44 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
}
if(!assertedToTheTheory && canBePropagated && !hasProof ){
- if(upperBound){
- Assert(bestImplied != d_partialModel.getUpperBoundConstraint(basic));
- d_linEq.propagateNonbasicsUpperBound(basic, bestImplied);
- }else{
- Assert(bestImplied != d_partialModel.getLowerBoundConstraint(basic));
- d_linEq.propagateNonbasicsLowerBound(basic, bestImplied);
- }
+ d_linEq.propagateBasicFromRow(bestImplied);
// I think this can be skipped if canBePropagated is true
//d_learnedBounds.push(bestImplied);
+ if(Debug.isOn("arith::prop")){
+ Debug("arith::prop") << "success " << bestImplied << endl;
+ d_partialModel.printModel(basic, Debug("arith::prop"));
+ }
return true;
}
+ if(Debug.isOn("arith::prop")){
+ Debug("arith::prop") << "failed " << basic << " " << bound << assertedToTheTheory << " " <<
+ canBePropagated << " " << hasProof << endl;
+ d_partialModel.printModel(basic, Debug("arith::prop"));
+ }
}
+ }else if(Debug.isOn("arith::prop")){
+ Debug("arith::prop") << "false " << bound << " ";
+ d_partialModel.printModel(basic, Debug("arith::prop"));
}
return false;
}
void TheoryArithPrivate::propagateCandidate(ArithVar basic){
bool success = false;
- if(d_partialModel.strictlyAboveLowerBound(basic) && d_linEq.hasLowerBounds(basic)){
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+
+ bool tryLowerBound =
+ d_partialModel.strictlyAboveLowerBound(basic) &&
+ d_linEq.rowLacksBound(ridx, false, basic) == NULL;
+
+ bool tryUpperBound =
+ d_partialModel.strictlyBelowUpperBound(basic) &&
+ d_linEq.rowLacksBound(ridx, true, basic) == NULL;
+
+ if(tryLowerBound){
success |= propagateCandidateLowerBound(basic);
}
- if(d_partialModel.strictlyBelowUpperBound(basic) && d_linEq.hasUpperBounds(basic)){
+ if(tryUpperBound){
success |= propagateCandidateUpperBound(basic);
}
if(success){
@@ -2652,6 +2758,8 @@ void TheoryArithPrivate::propagateCandidate(ArithVar basic){
void TheoryArithPrivate::propagateCandidates(){
TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
+ Debug("arith::prop") << "propagateCandidates begin" << endl;
+
Assert(d_candidateBasics.empty());
if(d_updatedBounds.empty()){ return; }
@@ -2685,6 +2793,292 @@ void TheoryArithPrivate::propagateCandidates(){
Assert(d_tableau.isBasic(candidate));
propagateCandidate(candidate);
}
+ Debug("arith::prop") << "propagateCandidates end" << endl << endl << endl;
+}
+
+void TheoryArithPrivate::propagateCandidatesNew(){
+ /* Four criteria must be met for progagation on a variable to happen using a row:
+ * 0: A new bound has to have been added to the row.
+ * 1: The hasBoundsCount for the row must be "full" or be full minus one variable
+ * (This is O(1) to check, but requires book keeping.)
+ * 2: The current assignment must be strictly smaller/greater than the current bound.
+ * assign(x) < upper(x)
+ * (This is O(1) to compute.)
+ * 3: There is a bound that is strictly smaller/greater than the current assignment.
+ * assign(x) < c for some x <= c literal
+ * (This is O(log n) to compute.)
+ * 4: The implied bound on x is strictly smaller/greater than the current bound.
+ * (This is O(n) to compute.)
+ */
+
+ TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
+ Debug("arith::prop") << "propagateCandidatesNew begin" << endl;
+
+ Assert(d_qflraStatus == Result::SAT);
+ if(d_updatedBounds.empty()){ return; }
+ dumpUpdatedBoundsToRows();
+ Assert(d_updatedBounds.empty());
+
+ if(!d_candidateRows.empty()){
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ }
+
+ while(!d_candidateRows.empty()){
+ RowIndex candidate = d_candidateRows.back();
+ d_candidateRows.pop_back();
+ propagateCandidateRow(candidate);
+ }
+ Debug("arith::prop") << "propagateCandidatesNew end" << endl << endl << endl;
+}
+
+bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
+ int cmp = ub ? d_partialModel.cmpAssignmentUpperBound(v)
+ : d_partialModel.cmpAssignmentLowerBound(v);
+ bool hasSlack = ub ? cmp < 0 : cmp > 0;
+ if(hasSlack){
+ ConstraintType t = ub ? UpperBound : LowerBound;
+ const DeltaRational& a = d_partialModel.getAssignment(v);
+
+ if(isInteger(v) && !a.isIntegral()){
+ return true;
+ }
+
+ Constraint strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
+ if(strongestPossible == NullConstraint){
+ return false;
+ }else{
+ bool assertedToTheTheory = strongestPossible->assertedToTheTheory();
+ bool canBePropagated = strongestPossible->canBePropagated();
+ bool hasProof = strongestPossible->hasProof();
+
+ return !assertedToTheTheory && canBePropagated && !hasProof;
+ }
+ }else{
+ return false;
+ }
+}
+
+bool TheoryArithPrivate::attemptSingleton(RowIndex ridx, bool rowUp){
+ Debug("arith::prop") << " attemptSingleton" << ridx;
+
+ const Tableau::Entry* ep;
+ ep = d_linEq.rowLacksBound(ridx, rowUp, ARITHVAR_SENTINEL);
+ Assert(ep != NULL);
+
+ ArithVar v = ep->getColVar();
+ const Rational& coeff = ep->getCoefficient();
+
+ // 0 = c * v + \sum rest
+ // Suppose rowUp
+ // - c * v = \sum rest \leq D
+ // if c > 0, v \geq -D/c so !vUp
+ // if c < 0, v \leq -D/c so vUp
+ // Suppose not rowUp
+ // - c * v = \sum rest \geq D
+ // if c > 0, v \leq -D/c so vUp
+ // if c < 0, v \geq -D/c so !vUp
+ bool vUp = (rowUp == ( coeff.sgn() < 0));
+
+ Debug("arith::prop") << " " << rowUp << " " << v << " " << coeff << " " << vUp << endl;
+ Debug("arith::prop") << " " << propagateMightSucceed(v, vUp) << endl;
+
+ if(propagateMightSucceed(v, vUp)){
+ DeltaRational dr = d_linEq.computeRowBound(ridx, rowUp, v);
+ DeltaRational bound = dr / (- coeff);
+ return tryToPropagate(ridx, rowUp, v, vUp, bound);
+ }
+ return false;
+}
+
+bool TheoryArithPrivate::attemptFull(RowIndex ridx, bool rowUp){
+ Debug("arith::prop") << " attemptFull" << ridx << endl;
+
+ vector<const Tableau::Entry*> candidates;
+
+ for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
+ const Tableau::Entry& e =*i;
+ const Rational& c = e.getCoefficient();
+ ArithVar v = e.getColVar();
+ bool vUp = (rowUp == (c.sgn() < 0));
+ if(propagateMightSucceed(v, vUp)){
+ candidates.push_back(&e);
+ }
+ }
+ if(candidates.empty()){ return false; }
+
+ const DeltaRational slack =
+ d_linEq.computeRowBound(ridx, rowUp, ARITHVAR_SENTINEL);
+ bool any = false;
+ vector<const Tableau::Entry*>::const_iterator i, iend;
+ for(i = candidates.begin(), iend = candidates.end(); i != iend; ++i){
+ const Tableau::Entry* ep = *i;
+ const Rational& c = ep->getCoefficient();
+ ArithVar v = ep->getColVar();
+
+ // See the comment for attemptSingleton()
+ bool activeUp = (rowUp == (c.sgn() > 0));
+ bool vUb = (rowUp == (c.sgn() < 0));
+
+ const DeltaRational& activeBound = activeUp ?
+ d_partialModel.getUpperBound(v):
+ d_partialModel.getLowerBound(v);
+
+ DeltaRational contribution = activeBound * c;
+ DeltaRational impliedBound = (slack - contribution)/(-c);
+
+ bool success = tryToPropagate(ridx, rowUp, v, vUb, impliedBound);
+ any |= success;
+ }
+ return any;
+}
+
+bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUb, const DeltaRational& bound){
+
+ bool weaker = vUb ? d_partialModel.strictlyLessThanUpperBound(v, bound):
+ d_partialModel.strictlyGreaterThanLowerBound(v, bound);
+ if(weaker){
+ ConstraintType t = vUb ? UpperBound : LowerBound;
+
+ if(isInteger(v)){
+ //cout << "maybe" << endl;
+ //cout << bound << endl;
+ }
+ Constraint implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
+ if(implied != NullConstraint){
+ return rowImplicationCanBeApplied(ridx, rowUp, implied);
+ }
+ }
+ return false;
+}
+
+Node flattenImplication(Node imp){
+ NodeBuilder<> nb(kind::OR);
+ Node left = imp[0];
+ Node right = imp[1];
+
+ if(left.getKind() == kind::AND){
+ for(Node::iterator i = left.begin(), iend = left.end(); i != iend; ++i) {
+ nb << (*i).negate();
+ }
+ }else{
+ nb << left.negate();
+ }
+
+ if(right.getKind() == kind::OR){
+ for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) {
+ nb << *i;
+ }
+ }else{
+ nb << right;
+ }
+
+ return nb;
+}
+
+bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint implied){
+ Assert(implied != NullConstraint);
+ ArithVar v = implied->getVariable();
+
+ bool assertedToTheTheory = implied->assertedToTheTheory();
+ bool canBePropagated = implied->canBePropagated();
+ bool hasProof = implied->hasProof();
+
+ Debug("arith::prop") << "arith::prop" << v
+ << " " << assertedToTheTheory
+ << " " << canBePropagated
+ << " " << hasProof
+ << endl;
+
+ if(implied->negationHasProof()){
+ Warning() << "the negation of " << implied << " : " << endl
+ << "has proof " << implied->getNegation() << endl
+ << implied->getNegation()->explainForConflict() << endl;
+ }
+
+ if(!assertedToTheTheory && canBePropagated && !hasProof ){
+ vector<Constraint> explain;
+ d_linEq.propagateRow(explain, ridx, rowUp, implied);
+ if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){
+ Node implication = implied->makeImplication(explain);
+ Node clause = flattenImplication(implication);
+ outputLemma(clause);
+ }else{
+ implied->impliedBy(explain);
+ }
+ return true;
+ }
+
+ if(Debug.isOn("arith::prop")){
+ Debug("arith::prop")
+ << "failed " << v << " " << assertedToTheTheory << " "
+ << canBePropagated << " " << hasProof << " " << implied << endl;
+ d_partialModel.printModel(v, Debug("arith::prop"));
+ }
+ return false;
+}
+
+double fRand(double fMin, double fMax)
+{
+ double f = (double)rand() / RAND_MAX;
+ return fMin + f * (fMax - fMin);
+}
+
+bool TheoryArithPrivate::propagateCandidateRow(RowIndex ridx){
+ BoundCounts hasCount = d_linEq.hasBoundCount(ridx);
+ uint32_t rowLength = d_tableau.getRowLength(ridx);
+
+ bool success = false;
+ static int instance = 0;
+ ++instance;
+
+ Debug("arith::prop")
+ << "propagateCandidateRow " << instance << " attempt " << rowLength << " " << hasCount << endl;
+
+ if(rowLength >= options::arithPropagateMaxLength()){
+ if(fRand(0.0,1.0) >= double(options::arithPropagateMaxLength())/rowLength){
+ return false;
+ }
+ }
+
+ if(hasCount.lowerBoundCount() == rowLength){
+ success |= attemptFull(ridx, false);
+ }else if(hasCount.lowerBoundCount() + 1 == rowLength){
+ success |= attemptSingleton(ridx, false);
+ }
+
+ if(hasCount.upperBoundCount() == rowLength){
+ success |= attemptFull(ridx, true);
+ }else if(hasCount.upperBoundCount() + 1 == rowLength){
+ success |= attemptSingleton(ridx, true);
+ }
+ return success;
+}
+
+void TheoryArithPrivate::dumpUpdatedBoundsToRows(){
+ Assert(d_candidateRows.empty());
+ DenseSet::const_iterator i = d_updatedBounds.begin();
+ DenseSet::const_iterator end = d_updatedBounds.end();
+ for(; i != end; ++i){
+ ArithVar var = *i;
+ if(d_tableau.isBasic(var)){
+ RowIndex ridx = d_tableau.basicToRowIndex(var);
+ d_candidateRows.softAdd(ridx);
+ }else{
+ Tableau::ColIterator basicIter = d_tableau.colIterator(var);
+ for(; !basicIter.atEnd(); ++basicIter){
+ const Tableau::Entry& entry = *basicIter;
+ RowIndex ridx = entry.getRowIndex();
+ d_candidateRows.softAdd(ridx);
+ }
+ }
+ }
+ d_updatedBounds.purge();
+}
+
+const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
+ RowIndex ridx = d_tableau.basicToRowIndex(basic);
+ return d_rowTracking[ridx];
}
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h
index 7b37a813f..22fc8d4a7 100644
--- a/src/theory/arith/theory_arith_private.h
+++ b/src/theory/arith/theory_arith_private.h
@@ -58,7 +58,7 @@
#include "theory/arith/dual_simplex.h"
#include "theory/arith/fc_simplex.h"
#include "theory/arith/soi_simplex.h"
-#include "theory/arith/pure_update_simplex.h"
+#include "theory/arith/attempt_solution_simplex.h"
#include "theory/arith/constraint.h"
@@ -105,7 +105,7 @@ private:
// TODO A better would be:
//context::CDO<bool> d_nlIncomplete;
- BoundCountingVector d_boundTracking;
+ BoundInfoMap d_rowTracking;
/**
* The constraint database associated with the theory.
@@ -132,7 +132,8 @@ private:
/** Static learner. */
ArithStaticLearner d_learner;
-
+ /** quantifiers engine */
+ QuantifiersEngine * d_quantEngine;
//std::vector<ArithVar> d_pool;
public:
void releaseArithVar(ArithVar v);
@@ -316,9 +317,9 @@ private:
/** This implements the Simplex decision procedure. */
DualSimplexDecisionProcedure d_dualSimplex;
- PureUpdateSimplexDecisionProcedure d_pureUpdate;
FCSimplexDecisionProcedure d_fcSimplex;
SumOfInfeasibilitiesSPD d_soiSimplex;
+ AttemptSolutionSDP d_attemptSolSimplex;
bool solveRealRelaxation(Theory::Effort effortLevel);
@@ -345,7 +346,8 @@ private:
Node axiomIteForTotalDivision(Node div_tot);
Node axiomIteForTotalIntDivision(Node int_div_like);
-
+ // handle linear /, div, mod, and also is_int, to_int
+ Node ppRewriteTerms(TNode atom);
public:
TheoryArithPrivate(TheoryArith& containing, context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
@@ -381,6 +383,8 @@ public:
void addSharedTerm(TNode n);
+ Node getModelValue(TNode var);
+
private:
/** The constant zero. */
@@ -430,6 +434,10 @@ public:
*/
ArithVar requestArithVar(TNode x, bool slack);
+public:
+ const BoundsInfo& boundsInfo(ArithVar basic) const;
+
+
private:
/** Initial (not context dependent) sets up for a variable.*/
void setupBasicValue(ArithVar x);
@@ -463,12 +471,25 @@ private:
/** Tracks the basic variables where propagation might be possible. */
DenseSet d_candidateBasics;
+ DenseSet d_candidateRows;
bool hasAnyUpdates() { return !d_updatedBounds.empty(); }
void clearUpdates();
void revertOutOfConflict();
+ void propagateCandidatesNew();
+ void dumpUpdatedBoundsToRows();
+ bool propagateCandidateRow(RowIndex rid);
+ bool propagateMightSucceed(ArithVar v, bool ub) const;
+ /** Attempt to perform a row propagation where there is at most 1 possible variable.*/
+ bool attemptSingleton(RowIndex ridx, bool rowUp);
+ /** Attempt to perform a row propagation where every variable is a potential candidate.*/
+ bool attemptFull(RowIndex ridx, bool rowUp);
+ bool tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUp, const DeltaRational& bound);
+ bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint bestImplied);
+
+
void propagateCandidates();
void propagateCandidate(ArithVar basic);
bool propagateCandidateBound(ArithVar basic, bool upperBound);
@@ -517,9 +538,9 @@ private:
std::vector<ArithVar>& variables);
/** Routine for debugging. Print the assertions the theory is aware of. */
- void debugPrintAssertions();
+ void debugPrintAssertions(std::ostream& out) const;
/** Debugging only routine. Prints the model. */
- void debugPrintModel();
+ void debugPrintModel(std::ostream& out) const;
inline LogicInfo getLogicInfo() const { return d_containing.getLogicInfo(); }
inline bool done() const { return d_containing.done(); }
@@ -553,6 +574,12 @@ private:
context::CDO<unsigned> d_cutCount;
context::CDHashSet<ArithVar, std::hash<ArithVar> > d_cutInContext;
+ context::CDO<bool> d_likelyIntegerInfeasible;
+
+
+ context::CDO<bool> d_guessedCoeffSet;
+ ArithRatPairVec d_guessedCoeffs;
+
/** These fields are designed to be accessible to TheoryArith methods. */
class Statistics {
public:
diff --git a/src/theory/arith/theory_arith_type_rules.h b/src/theory/arith/theory_arith_type_rules.h
index cc8451f8b..45e18fe0d 100644
--- a/src/theory/arith/theory_arith_type_rules.h
+++ b/src/theory/arith/theory_arith_type_rules.h
@@ -62,12 +62,37 @@ public:
}
}
}
- Kind k = n.getKind();
- bool isDivision = k == kind::DIVISION || k == kind::DIVISION_TOTAL;
- return (isInteger && !isDivision ? integerType : realType);
+ switch(Kind k = n.getKind()) {
+ case kind::TO_REAL:
+ return realType;
+ case kind::TO_INTEGER:
+ return integerType;
+ default: {
+ bool isDivision = k == kind::DIVISION || k == kind::DIVISION_TOTAL;
+ return (isInteger && !isDivision ? integerType : realType);
+ }
+ }
}
};/* class ArithOperatorTypeRule */
+class IntOperatorTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator child_it = n.begin();
+ TNode::iterator child_it_end = n.end();
+ if(check) {
+ for(; child_it != child_it_end; ++child_it) {
+ TypeNode childType = (*child_it).getType(check);
+ if (!childType.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer subterm");
+ }
+ }
+ }
+ return nodeManager->integerType();
+ }
+};/* class IntOperatorTypeRule */
+
class ArithPredicateTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -87,6 +112,34 @@ public:
}
};/* class ArithPredicateTypeRule */
+class ArithUnaryPredicateTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isReal()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an arithmetic term");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class ArithUnaryPredicateTypeRule */
+
+class IntUnaryPredicateTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer term");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class IntUnaryPredicateTypeRule */
+
class SubrangeProperties {
public:
inline static Cardinality computeCardinality(TypeNode type) {
diff --git a/src/theory/arrays/Makefile.am b/src/theory/arrays/Makefile.am
index ec834522f..77f102cf8 100644
--- a/src/theory/arrays/Makefile.am
+++ b/src/theory/arrays/Makefile.am
@@ -16,9 +16,7 @@ libarrays_la_SOURCES = \
array_info.h \
array_info.cpp \
static_fact_manager.h \
- static_fact_manager.cpp \
- theory_arrays_model.h \
- theory_arrays_model.cpp
+ static_fact_manager.cpp
EXTRA_DIST = \
kinds
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 801893107..98346d0e3 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -21,7 +21,6 @@
#include <map>
#include "theory/rewriter.h"
#include "expr/command.h"
-#include "theory/arrays/theory_arrays_model.h"
#include "theory/model.h"
#include "theory/arrays/options.h"
#include "smt/logic_exception.h"
@@ -464,7 +463,9 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
}
case kind::STORE: {
// Invariant: array terms should be preregistered before being added to the equality engine
- Assert(!d_equalityEngine.hasTerm(node));
+ if (d_equalityEngine.hasTerm(node)) {
+ break;
+ }
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
TNode a = d_equalityEngine.getRepresentative(node[0]);
@@ -493,7 +494,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
}
case kind::STORE_ALL: {
throw LogicException("Array theory solver does not yet support assertions using constant array value");
- }
+ }
default:
// Variables etc
if (node.getType().isArray()) {
@@ -588,7 +589,10 @@ void TheoryArrays::computeCareGraph()
}
}
}
- if (options::arraysModelBased()) return;
+ if (options::arraysModelBased()) {
+ checkModel(EFFORT_COMBINATION);
+ return;
+ }
if (d_sharedTerms) {
vector< pair<TNode, TNode> > currentPairs;
@@ -1009,7 +1013,7 @@ void TheoryArrays::checkModel(Effort e)
Assert(d_skolemAssertions.empty());
Assert(d_lemmas.empty());
- if (fullEffort(e)) {
+ if (combination(e)) {
// Add constraints for shared terms
context::CDList<TNode>::const_iterator shared_it = shared_terms_begin(), shared_it_end = shared_terms_end(), shared_it2;
Node modelVal, modelVal2, d;
@@ -1061,9 +1065,10 @@ void TheoryArrays::checkModel(Effort e)
unsigned constraintIdx;
Node assertion, assertionToCheck;
vector<TNode> assumptions;
- // int numrestarts = 0;
- while (true) {
- // ++numrestarts;
+ int numrestarts = 0;
+ while (true || numrestarts < 1 || fullEffort(e) || combination(e)) {
+ ++numrestarts;
+ d_out->safePoint();
int level = getSatContext()->getLevel();
d_getModelValCache.clear();
for (constraintIdx = 0; constraintIdx < d_modelConstraints.size(); ++constraintIdx) {
@@ -1076,7 +1081,7 @@ void TheoryArrays::checkModel(Effort e)
if (constraintIdx == d_modelConstraints.size()) {
break;
}
-
+
if (assertion.getKind() == kind::EQUAL && assertion[0].getType().isArray()) {
assertionToCheck = solveWrite(expandStores(assertion[0], assumptions).eqNode(expandStores(assertion[1], assumptions)), true, true, false);
if (assertionToCheck.getKind() == kind::AND &&
@@ -1202,20 +1207,20 @@ void TheoryArrays::checkModel(Effort e)
}
{
// generate lemma
- // if (all.size() == 0) {
- // d_lemmas.push_back(decision.negate());
- // }
- // else {
- // NodeBuilder<> disjunction(kind::OR);
- // std::set<TNode>::const_iterator it = all.begin();
- // std::set<TNode>::const_iterator it_end = all.end();
- // while (it != it_end) {
- // disjunction << (*it).negate();
- // ++it;
- // }
- // disjunction << decision.negate();
- // d_lemmas.push_back(disjunction);
- // }
+ if (all.size() == 0) {
+ d_lemmas.push_back(decision.negate());
+ }
+ else {
+ NodeBuilder<> disjunction(kind::OR);
+ std::set<TNode>::const_iterator it = all.begin();
+ std::set<TNode>::const_iterator it_end = all.end();
+ while (it != it_end) {
+ disjunction << (*it).negate();
+ ++it;
+ }
+ disjunction << decision.negate();
+ d_lemmas.push_back(disjunction);
+ }
}
d_equalityEngine.assertEquality(decision, eq, explanation);
if (!eq) decision = decision.notNode();
@@ -1268,6 +1273,13 @@ void TheoryArrays::checkModel(Effort e)
}
d_skolemIndex = d_skolemIndex + 1;
}
+ // Reregister stores
+ if (assertionToCheck != assertion &&
+ assertionToCheck.getKind() == kind::AND &&
+ assertionToCheck[assertionToCheck.getNumChildren()-1].getKind() == kind::EQUAL) {
+ TNode s = assertionToCheck[assertionToCheck.getNumChildren()-1][0];
+ preRegisterStores(s);
+ }
}
if (d_conflict) {
break;
@@ -1294,10 +1306,10 @@ void TheoryArrays::checkModel(Effort e)
d_skolemIndex = 0;
while (!d_lemmas.empty()) {
Debug("arrays-model-based") << "Sending lemma: " << d_lemmas.back() << endl;
- d_out->lemma(d_lemmas.back());
+ d_out->splitLemma(d_lemmas.back());
#ifdef CVC4_ASSERTIONS
- Assert(d_lemmasSaved.find(d_lemmas.back()) == d_lemmasSaved.end());
- d_lemmasSaved.insert(d_lemmas.back());
+ // Assert(d_lemmasSaved.find(d_lemmas.back()) == d_lemmasSaved.end());
+ // d_lemmasSaved.insert(d_lemmas.back());
#endif
d_lemmas.pop_back();
}
@@ -1416,7 +1428,7 @@ Node TheoryArrays::getModelValRec(TNode node)
}
++d_numGetModelValConflicts;
getSatContext()->pop();
- }
+ }
++te;
if (te.isFinished()) {
Assert(false);
@@ -1453,7 +1465,7 @@ bool TheoryArrays::hasLoop(TNode node, TNode target)
return true;
}
}
-
+
return false;
}
@@ -1633,9 +1645,14 @@ bool TheoryArrays::setModelVal(TNode node, TNode val, bool invert, bool explain,
return true;
}
}
- getSatContext()->push();
Node d = node.eqNode(val);
- d_decisions.push_back(invert ? d.notNode() : d);
+ Node r = Rewriter::rewrite(d);
+ if (r.isConst()) {
+ d_equalityEngine.assertEquality(d, r == d_true, d_true);
+ return ((r == d_true) == (!invert));
+ }
+ getSatContext()->push();
+ d_decisions.push_back(invert ? d.negate() : d);
d_equalityEngine.assertEquality(d, !invert, d_decisions.back());
Debug("arrays-model-based") << "Asserting " << d_decisions.back() << " with explanation " << d_decisions.back() << endl;
++d_numSetModelValSplits;
@@ -1667,7 +1684,7 @@ bool TheoryArrays::setModelVal(TNode node, TNode val, bool invert, bool explain,
d_decisions.pop_back();
d_permRef.push_back(explanation);
d = d.negate();
- Debug("arrays-model-based") << "Asserting learned literal " << d << " with explanation " << explanation << endl;
+ Debug("arrays-model-based") << "Asserting learned literal2 " << d << " with explanation " << explanation << endl;
bool eq = true;
if (d.getKind() == kind::NOT) {
d = d[0];
diff --git a/src/theory/arrays/theory_arrays_model.cpp b/src/theory/arrays/theory_arrays_model.cpp
deleted file mode 100644
index b5c81ef69..000000000
--- a/src/theory/arrays/theory_arrays_model.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/********************* */
-/*! \file theory_arrays_model.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of theory_arrays_model class
- **/
-
-#include "theory/theory_engine.h"
-#include "theory/arrays/theory_arrays_model.h"
-#include "theory/model.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::arrays;
-
-ArrayModel::ArrayModel( Node arr, TheoryModel* m ) : d_arr( arr ){
- d_base_arr = arr;
- while( d_base_arr.getKind()==STORE ){
- Node ri = m->getRepresentative( d_base_arr[1] );
- if( d_values.find( ri )==d_values.end() ){
- d_values[ ri ] = m->getRepresentative( d_base_arr[2] );
- }
- d_base_arr = d_base_arr[0];
- }
-}
-
-Node ArrayModel::getValue( TheoryModel* m, Node i ){
- i = m->getRepresentative( i );
- std::map< Node, Node >::iterator it = d_values.find( i );
- if( it!=d_values.end() ){
- return it->second;
- }else{
- return NodeManager::currentNM()->mkNode( SELECT, getArrayValue(), i );
- //return d_default_value; //TODO: guarantee I can return this here
- }
-}
-
-void ArrayModel::setValue( TheoryModel* m, Node i, Node e ){
- Node ri = m->getRepresentative( i );
- if( d_values.find( ri )==d_values.end() ){
- d_values[ ri ] = m->getRepresentative( e );
- }
-}
-
-void ArrayModel::setDefaultArray( Node arr ){
- d_base_arr = arr;
-}
-
-Node ArrayModel::getArrayValue(){
- Node curr = d_base_arr;
- for( std::map< Node, Node >::iterator it = d_values.begin(); it != d_values.end(); ++it ){
- curr = NodeManager::currentNM()->mkNode( STORE, curr, it->first, it->second );
- }
- return curr;
-}
diff --git a/src/theory/arrays/theory_arrays_model.h b/src/theory/arrays/theory_arrays_model.h
deleted file mode 100644
index 66dc80568..000000000
--- a/src/theory/arrays/theory_arrays_model.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/********************* */
-/*! \file theory_arrays_model.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief MODEL for theory of arrays
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY_ARRAYS_MODEL_H
-#define __CVC4__THEORY_ARRAYS_MODEL_H
-
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-class TheoryModel;
-
-namespace arrays {
-
-class ArrayModel{
-protected:
- /** the array this model is for */
- Node d_arr;
-public:
- ArrayModel(){}
- ArrayModel( Node arr, TheoryModel* m );
- ~ArrayModel() {}
-public:
- /** pre-defined values */
- std::map< Node, Node > d_values;
- /** base array */
- Node d_base_arr;
- /** get value, return arguments that the value depends on */
- Node getValue( TheoryModel* m, Node i );
- /** set value */
- void setValue( TheoryModel* m, Node i, Node e );
- /** set default */
- void setDefaultArray( Node arr );
-public:
- /** get array value */
- Node getArrayValue();
-};/* class ArrayModel */
-
-}
-}
-}
-
-#endif \ No newline at end of file
diff --git a/src/theory/arrays/theory_arrays_rewriter.h b/src/theory/arrays/theory_arrays_rewriter.h
index 18bbef8cf..5df06bda8 100644
--- a/src/theory/arrays/theory_arrays_rewriter.h
+++ b/src/theory/arrays/theory_arrays_rewriter.h
@@ -36,6 +36,10 @@ namespace attr {
typedef expr::Attribute<attr::ArrayConstantMostFrequentValueCountTag, uint64_t> ArrayConstantMostFrequentValueCountAttr;
typedef expr::Attribute<attr::ArrayConstantMostFrequentValueTag, Node> ArrayConstantMostFrequentValueAttr;
+static inline Node mkEqNode(Node a, Node b) {
+ return a.getType().isBoolean() ? a.iffNode(b) : a.eqNode(b);
+}
+
class TheoryArraysRewriter {
static Node normalizeConstant(TNode node) {
return normalizeConstant(node, node[1].getType().getCardinality());
@@ -244,7 +248,7 @@ public:
val = false;
}
else {
- n = Rewriter::rewrite(store[1].eqNode(index));
+ n = Rewriter::rewrite(mkEqNode(store[1], index));
if (n.getKind() != kind::CONST_BOOLEAN) {
break;
}
@@ -301,7 +305,7 @@ public:
val = false;
}
else {
- Node eqRewritten = Rewriter::rewrite(store[1].eqNode(index));
+ Node eqRewritten = Rewriter::rewrite(mkEqNode(store[1], index));
if (eqRewritten.getKind() != kind::CONST_BOOLEAN) {
Trace("arrays-postrewrite") << "Arrays::postRewrite returning " << node << std::endl;
return RewriteResponse(REWRITE_DONE, node);
@@ -340,7 +344,7 @@ public:
val = false;
}
else {
- n = Rewriter::rewrite(store[1].eqNode(index));
+ n = Rewriter::rewrite(mkEqNode(store[1], index));
if (n.getKind() != kind::CONST_BOOLEAN) {
break;
}
@@ -416,7 +420,7 @@ public:
val = false;
}
else {
- n = Rewriter::rewrite(store[1].eqNode(index));
+ n = Rewriter::rewrite(mkEqNode(store[1], index));
if (n.getKind() != kind::CONST_BOOLEAN) {
break;
}
@@ -466,7 +470,7 @@ public:
val = false;
}
else {
- Node eqRewritten = Rewriter::rewrite(store[1].eqNode(index));
+ Node eqRewritten = Rewriter::rewrite(mkEqNode(store[1], index));
if (eqRewritten.getKind() != kind::CONST_BOOLEAN) {
break;
}
diff --git a/src/theory/atom_requests.cpp b/src/theory/atom_requests.cpp
new file mode 100644
index 000000000..3d111f9f8
--- /dev/null
+++ b/src/theory/atom_requests.cpp
@@ -0,0 +1,62 @@
+#include "theory/atom_requests.h"
+
+using namespace CVC4;
+
+AtomRequests::AtomRequests(context::Context* context)
+: d_allRequests(context)
+, d_requests(context)
+, d_triggerToRequestMap(context)
+{}
+
+AtomRequests::element_index AtomRequests::getList(TNode trigger) const {
+ trigger_to_list_map::const_iterator find = d_triggerToRequestMap.find(trigger);
+ if (find == d_triggerToRequestMap.end()) {
+ return null_index;
+ } else {
+ return (*find).second;
+ }
+}
+
+bool AtomRequests::isTrigger(TNode atom) const {
+ return getList(atom) != null_index;
+}
+
+AtomRequests::atom_iterator AtomRequests::getAtomIterator(TNode trigger) const {
+ return atom_iterator(*this, getList(trigger));
+}
+
+void AtomRequests::add(TNode triggerAtom, TNode atomToSend, theory::TheoryId toTheory) {
+
+ Debug("theory::atoms") << "AtomRequests::add(" << triggerAtom << ", " << atomToSend << ", " << toTheory << ")" << std::endl;
+
+ Request request(atomToSend, toTheory);
+
+ if (d_allRequests.find(request) != d_allRequests.end()) {
+ // Have it already
+ Debug("theory::atoms") << "AtomRequests::add(" << triggerAtom << ", " << atomToSend << ", " << toTheory << "): already there" << std::endl;
+ return;
+ }
+ Debug("theory::atoms") << "AtomRequests::add(" << triggerAtom << ", " << atomToSend << ", " << toTheory << "): adding" << std::endl;
+
+ /// Mark the new request
+ d_allRequests.insert(request);
+
+ // Index of the new request in the list of trigger
+ element_index index = d_requests.size();
+ element_index previous = getList(triggerAtom);
+ d_requests.push_back(Element(request, previous));
+ d_triggerToRequestMap[triggerAtom] = index;
+}
+
+bool AtomRequests::atom_iterator::done() const {
+ return index == null_index;
+}
+
+void AtomRequests::atom_iterator::next() {
+ index = requests.d_requests[index].previous;
+}
+
+const AtomRequests::Request& AtomRequests::atom_iterator::get() const {
+ return requests.d_requests[index].request;
+}
+
diff --git a/src/theory/atom_requests.h b/src/theory/atom_requests.h
new file mode 100644
index 000000000..99878125a
--- /dev/null
+++ b/src/theory/atom_requests.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "expr/node.h"
+#include "theory/theory.h"
+#include "context/cdlist.h"
+#include "context/cdhashset.h"
+#include "context/cdhashmap.h"
+
+namespace CVC4 {
+
+class AtomRequests {
+
+public:
+
+ /** Which atom and where to send it */
+ struct Request {
+ /** Atom */
+ Node atom;
+ /** Where to send it */
+ theory::TheoryId toTheory;
+
+ Request(TNode atom, theory::TheoryId toTheory)
+ : atom(atom), toTheory(toTheory) {}
+ Request()
+ : toTheory(theory::THEORY_LAST)
+ {}
+
+ bool operator == (const Request& other) const {
+ return atom == other.atom && toTheory == other.toTheory;
+ }
+
+ size_t hash() const {
+ return atom.getId();
+ }
+
+ };
+
+ AtomRequests(context::Context* context);
+
+ /** Mark the atom to be sent to a theory, when the trigger atom gets assigned */
+ void add(TNode triggerAtom, TNode atomToSend, theory::TheoryId toTheory);
+
+ /** Returns true if the node is a trigger and has a list of atoms to send */
+ bool isTrigger(TNode atom) const;
+
+ /** Indices in lists */
+ typedef size_t element_index;
+
+ class atom_iterator {
+ const AtomRequests& requests;
+ element_index index;
+ friend class AtomRequests;
+ atom_iterator(const AtomRequests& requests, element_index start)
+ : requests(requests), index(start) {}
+ public:
+ /** Is this iterator done */
+ bool done() const;
+ /** Go to the next element */
+ void next();
+ /** Get the actual request */
+ const Request& get() const;
+ };
+
+ atom_iterator getAtomIterator(TNode trigger) const;
+
+private:
+
+ struct RequestHashFunction {
+ size_t operator () (const Request& r) const {
+ return r.hash();
+ }
+ };
+
+ /** Set of all requests so we don't add twice */
+ context::CDHashSet<Request, RequestHashFunction> d_allRequests;
+
+ static const element_index null_index = -1;
+
+ struct Element {
+ /** Current request */
+ Request request;
+ /** Previous request */
+ element_index previous;
+
+ Element(const Request& request, element_index previous)
+ : request(request), previous(previous)
+ {}
+ };
+
+ /** We index the requests in this vector, it's a list */
+ context::CDList<Element> d_requests;
+
+ typedef context::CDHashMap<Node, element_index, NodeHashFunction> trigger_to_list_map;
+
+ /** Map from triggers, to the list of elements they trigger */
+ trigger_to_list_map d_triggerToRequestMap;
+
+ /** Get the list index of the trigger */
+ element_index getList(TNode trigger) const;
+
+};
+
+}
+
+
+
+
diff --git a/src/theory/booleans/theory_bool.cpp b/src/theory/booleans/theory_bool.cpp
index 3e75dd258..895f4a279 100644
--- a/src/theory/booleans/theory_bool.cpp
+++ b/src/theory/booleans/theory_bool.cpp
@@ -19,6 +19,7 @@
#include "theory/booleans/circuit_propagator.h"
#include "theory/valuation.h"
#include "util/boolean_simplification.h"
+#include "theory/substitutions.h"
#include <vector>
#include <stack>
diff --git a/src/theory/builtin/kinds b/src/theory/builtin/kinds
index fca79aff0..b51feea6d 100644
--- a/src/theory/builtin/kinds
+++ b/src/theory/builtin/kinds
@@ -300,7 +300,12 @@ operator SEXPR 0: "a symbolic expression"
operator LAMBDA 2 "lambda"
-parameterized CHAIN BUILTIN 2: "chain operator"
+parameterized CHAIN CHAIN_OP 2: "chained operator"
+constant CHAIN_OP \
+ ::CVC4::Chain \
+ ::CVC4::ChainHashFunction \
+ "util/chain.h" \
+ "the chained operator"
constant TYPE_CONSTANT \
::CVC4::TypeConstant \
@@ -321,29 +326,13 @@ well-founded SEXPR_TYPE \
"::CVC4::theory::builtin::SExprProperties::mkGroundTerm(%TYPE%)" \
"theory/builtin/theory_builtin_type_rules.h"
-# These will eventually move to a theory of strings.
-#
-# For now these are unbounded strings over a fixed, finite alphabet
-# (this may change).
-sort STRING_TYPE \
- Cardinality::INTEGERS \
- well-founded \
- "NodeManager::currentNM()->mkConst(::std::string())" \
- "string" \
- "String type"
-constant CONST_STRING \
- ::std::string \
- ::CVC4::StringHashFunction \
- "util/hash.h" \
- "a string of characters"
-typerule CONST_STRING ::CVC4::theory::builtin::StringConstantTypeRule
-
typerule APPLY ::CVC4::theory::builtin::ApplyTypeRule
typerule EQUAL ::CVC4::theory::builtin::EqualityTypeRule
typerule DISTINCT ::CVC4::theory::builtin::DistinctTypeRule
typerule SEXPR ::CVC4::theory::builtin::SExprTypeRule
typerule LAMBDA ::CVC4::theory::builtin::LambdaTypeRule
typerule CHAIN ::CVC4::theory::builtin::ChainTypeRule
+typerule CHAIN_OP ::CVC4::theory::builtin::ChainedOperatorTypeRule
constant SUBTYPE_TYPE \
::CVC4::Predicate \
diff --git a/src/theory/builtin/theory_builtin_rewriter.cpp b/src/theory/builtin/theory_builtin_rewriter.cpp
index 4d62ce511..392e146ba 100644
--- a/src/theory/builtin/theory_builtin_rewriter.cpp
+++ b/src/theory/builtin/theory_builtin_rewriter.cpp
@@ -16,6 +16,7 @@
**/
#include "theory/builtin/theory_builtin_rewriter.h"
+#include "util/chain.h"
using namespace std;
@@ -53,7 +54,7 @@ Node TheoryBuiltinRewriter::blastChain(TNode in) {
Assert(in.getKind() == kind::CHAIN);
- Kind chainedOp = in.getOperator().getConst<Kind>();
+ Kind chainedOp = in.getOperator().getConst<Chain>().getOperator();
if(in.getNumChildren() == 2) {
// if this is the case exactly 1 pair will be generated so the
diff --git a/src/theory/builtin/theory_builtin_type_rules.h b/src/theory/builtin/theory_builtin_type_rules.h
index 2a4e07528..c7143bdeb 100644
--- a/src/theory/builtin/theory_builtin_type_rules.h
+++ b/src/theory/builtin/theory_builtin_type_rules.h
@@ -146,14 +146,6 @@ public:
}
};/* class AbstractValueTypeRule */
-class StringConstantTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
- Assert(n.getKind() == kind::CONST_STRING);
- return nodeManager->stringType();
- }
-};/* class StringConstantTypeRule */
-
class LambdaTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
@@ -220,6 +212,14 @@ public:
}
};/* class ChainTypeRule */
+class ChainedOperatorTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
+ Assert(n.getKind() == kind::CHAIN_OP);
+ return nodeManager->getType(nodeManager->operatorOf(n.getConst<Chain>().getOperator()), check);
+ }
+};/* class ChainedOperatorTypeRule */
+
class SortProperties {
public:
inline static bool isWellFounded(TypeNode type) {
diff --git a/src/theory/bv/bitblaster.cpp b/src/theory/bv/bitblaster.cpp
index 8579012ab..d17dd588f 100644
--- a/src/theory/bv/bitblaster.cpp
+++ b/src/theory/bv/bitblaster.cpp
@@ -12,7 +12,7 @@
** \brief [[ Add one-line brief description here ]]
**
** [[ Add lengthier description here ]]
- **
+ **
**/
#include "bitblaster.h"
@@ -29,7 +29,7 @@
using namespace std;
using namespace CVC4::theory::bv::utils;
-using namespace CVC4::context;
+using namespace CVC4::context;
using namespace CVC4::prop;
namespace CVC4 {
@@ -37,20 +37,20 @@ namespace theory {
namespace bv{
std::string toString(Bits& bits) {
- ostringstream os;
+ ostringstream os;
for (int i = bits.size() - 1; i >= 0; --i) {
TNode bit = bits[i];
if (bit.getKind() == kind::CONST_BOOLEAN) {
os << (bit.getConst<bool>() ? "1" : "0");
} else {
- os << bit<< " ";
+ os << bit<< " ";
}
}
os <<"\n";
-
- return os.str();
+
+ return os.str();
}
-/////// Bitblaster
+/////// Bitblaster
Bitblaster::Bitblaster(context::Context* c, bv::TheoryBV* bv) :
d_bv(bv),
@@ -64,38 +64,41 @@ Bitblaster::Bitblaster(context::Context* c, bv::TheoryBV* bv) :
d_cnfStream = new TseitinCnfStream(d_satSolver, new NullRegistrar(), new Context());
MinisatNotify* notify = new MinisatNotify(d_cnfStream, bv);
- d_satSolver->setNotify(notify);
+ d_satSolver->setNotify(notify);
// initializing the bit-blasting strategies
- initAtomBBStrategies();
- initTermBBStrategies();
+ initAtomBBStrategies();
+ initTermBBStrategies();
}
Bitblaster::~Bitblaster() {
delete d_cnfStream;
- delete d_satSolver;
+ delete d_satSolver;
}
-/**
+/**
* Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver
* NOTE: duplicate clauses are not detected because of marker literal
* @param node the atom to be bitblasted
- *
+ *
*/
void Bitblaster::bbAtom(TNode node) {
node = node.getKind() == kind::NOT? node[0] : node;
-
+
if (hasBBAtom(node)) {
- return;
+ return;
}
// make sure it is marked as an atom
- addAtom(node);
+ addAtom(node);
- Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+ Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
++d_statistics.d_numAtoms;
// the bitblasted definition of the atom
- Node atom_bb = Rewriter::rewrite(d_atomBBStrategies[node.getKind()](node, this));
+ Node normalized = Rewriter::rewrite(node);
+ Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
+ Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
+ normalized;
// asserting that the atom is true iff the definition holds
Node atom_definition = mkNode(kind::IFF, node, atom_bb);
@@ -123,14 +126,14 @@ void Bitblaster::bbTerm(TNode node, Bits& bits) {
return;
}
- Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
+ Debug("bitvector-bitblast") << "Bitblasting node " << node <<"\n";
++d_statistics.d_numTerms;
d_termBBStrategies[node.getKind()] (node, bits,this);
-
+
Assert (bits.size() == utils::getSize(node));
- cacheTermDef(node, bits);
+ cacheTermDef(node, bits);
}
Node Bitblaster::bbOptimize(TNode node) {
@@ -139,21 +142,21 @@ Node Bitblaster::bbOptimize(TNode node) {
if (node.getKind() == kind::BITVECTOR_PLUS) {
if (RewriteRule<BBPlusNeg>::applies(node)) {
Node res = RewriteRule<BBPlusNeg>::run<false>(node);
- return res;
+ return res;
}
// if (RewriteRule<BBFactorOut>::applies(node)) {
// Node res = RewriteRule<BBFactorOut>::run<false>(node);
- // return res;
- // }
+ // return res;
+ // }
} else if (node.getKind() == kind::BITVECTOR_MULT) {
if (RewriteRule<MultPow2>::applies(node)) {
Node res = RewriteRule<MultPow2>::run<false>(node);
- return res;
+ return res;
}
}
-
- return node;
+
+ return node;
}
/// Public methods
@@ -170,31 +173,31 @@ void Bitblaster::explain(TNode atom, std::vector<TNode>& explanation) {
std::vector<SatLiteral> literal_explanation;
d_satSolver->explain(d_cnfStream->getLiteral(atom), literal_explanation);
for (unsigned i = 0; i < literal_explanation.size(); ++i) {
- explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
+ explanation.push_back(d_cnfStream->getNode(literal_explanation[i]));
}
}
-/**
+/*
* Asserts the clauses corresponding to the atom to the Sat Solver
* by turning on the marker literal (i.e. setting it to false)
* @param node the atom to be asserted
- *
+ *
*/
-
+
bool Bitblaster::propagate() {
return d_satSolver->propagate() == prop::SAT_VALUE_TRUE;
}
bool Bitblaster::assertToSat(TNode lit, bool propagate) {
// strip the not
- TNode atom;
+ TNode atom;
if (lit.getKind() == kind::NOT) {
- atom = lit[0];
+ atom = lit[0];
} else {
- atom = lit;
+ atom = lit;
}
-
+
Assert (hasBBAtom(atom));
SatLiteral markerLit = d_cnfStream->getLiteral(atom);
@@ -202,9 +205,9 @@ bool Bitblaster::assertToSat(TNode lit, bool propagate) {
if(lit.getKind() == kind::NOT) {
markerLit = ~markerLit;
}
-
+
Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat asserting node: " << atom <<"\n";
- Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat with literal: " << markerLit << "\n";
+ Debug("bitvector-bb") << "TheoryBV::Bitblaster::assertToSat with literal: " << markerLit << "\n";
SatValue ret = d_satSolver->assertAssumption(markerLit, propagate);
@@ -214,13 +217,13 @@ bool Bitblaster::assertToSat(TNode lit, bool propagate) {
return ret == prop::SAT_VALUE_TRUE;
}
-/**
- * Calls the solve method for the Sat Solver.
+/**
+ * Calls the solve method for the Sat Solver.
* passing it the marker literals to be asserted
- *
+ *
* @return true for sat, and false for unsat
*/
-
+
bool Bitblaster::solve(bool quick_solve) {
if (Trace.isOn("bitvector")) {
Trace("bitvector") << "Bitblaster::solve() asserted atoms ";
@@ -229,24 +232,24 @@ bool Bitblaster::solve(bool quick_solve) {
Trace("bitvector") << " " << d_cnfStream->getNode(*it) << "\n";
}
}
- Debug("bitvector") << "Bitblaster::solve() asserted atoms " << d_assertedAtoms.size() <<"\n";
- return SAT_VALUE_TRUE == d_satSolver->solve();
+ Debug("bitvector") << "Bitblaster::solve() asserted atoms " << d_assertedAtoms.size() <<"\n";
+ return SAT_VALUE_TRUE == d_satSolver->solve();
}
void Bitblaster::getConflict(std::vector<TNode>& conflict) {
SatClause conflictClause;
d_satSolver->getUnsatCore(conflictClause);
-
+
for (unsigned i = 0; i < conflictClause.size(); i++) {
- SatLiteral lit = conflictClause[i];
+ SatLiteral lit = conflictClause[i];
TNode atom = d_cnfStream->getNode(lit);
- Node not_atom;
+ Node not_atom;
if (atom.getKind() == kind::NOT) {
not_atom = atom[0];
} else {
- not_atom = NodeManager::currentNM()->mkNode(kind::NOT, atom);
+ not_atom = NodeManager::currentNM()->mkNode(kind::NOT, atom);
}
- conflict.push_back(not_atom);
+ conflict.push_back(not_atom);
}
}
@@ -256,9 +259,9 @@ void Bitblaster::getConflict(std::vector<TNode>& conflict) {
void Bitblaster::initAtomBBStrategies() {
for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
- d_atomBBStrategies[i] = UndefinedAtomBBStrategy;
+ d_atomBBStrategies[i] = UndefinedAtomBBStrategy;
}
-
+
/// setting default bb strategies for atoms
d_atomBBStrategies [ kind::EQUAL ] = DefaultEqBB;
d_atomBBStrategies [ kind::BITVECTOR_ULT ] = DefaultUltBB;
@@ -269,7 +272,7 @@ void Bitblaster::initAtomBBStrategies() {
d_atomBBStrategies [ kind::BITVECTOR_SLE ] = DefaultSleBB;
d_atomBBStrategies [ kind::BITVECTOR_SGT ] = DefaultSgtBB;
d_atomBBStrategies [ kind::BITVECTOR_SGE ] = DefaultSgeBB;
-
+
}
void Bitblaster::initTermBBStrategies() {
@@ -278,7 +281,7 @@ void Bitblaster::initTermBBStrategies() {
for (int i = 0 ; i < kind::LAST_KIND; ++i ) {
d_termBBStrategies[i] = DefaultVarBB;
}
-
+
/// setting default bb strategies for terms:
// d_termBBStrategies [ kind::VARIABLE ] = DefaultVarBB;
d_termBBStrategies [ kind::CONST_BITVECTOR ] = DefaultConstBB;
@@ -295,13 +298,13 @@ void Bitblaster::initTermBBStrategies() {
d_termBBStrategies [ kind::BITVECTOR_PLUS ] = DefaultPlusBB;
d_termBBStrategies [ kind::BITVECTOR_SUB ] = DefaultSubBB;
d_termBBStrategies [ kind::BITVECTOR_NEG ] = DefaultNegBB;
- d_termBBStrategies [ kind::BITVECTOR_UDIV ] = UndefinedTermBBStrategy;
- d_termBBStrategies [ kind::BITVECTOR_UREM ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_UDIV ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_UREM ] = UndefinedTermBBStrategy;
d_termBBStrategies [ kind::BITVECTOR_UDIV_TOTAL ] = DefaultUdivBB;
d_termBBStrategies [ kind::BITVECTOR_UREM_TOTAL ] = DefaultUremBB;
- d_termBBStrategies [ kind::BITVECTOR_SDIV ] = UndefinedTermBBStrategy;
- d_termBBStrategies [ kind::BITVECTOR_SREM ] = UndefinedTermBBStrategy;
- d_termBBStrategies [ kind::BITVECTOR_SMOD ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_SDIV ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_SREM ] = UndefinedTermBBStrategy;
+ d_termBBStrategies [ kind::BITVECTOR_SMOD ] = UndefinedTermBBStrategy;
d_termBBStrategies [ kind::BITVECTOR_SHL ] = DefaultShlBB;
d_termBBStrategies [ kind::BITVECTOR_LSHR ] = DefaultLshrBB;
d_termBBStrategies [ kind::BITVECTOR_ASHR ] = DefaultAshrBB;
@@ -313,22 +316,22 @@ void Bitblaster::initTermBBStrategies() {
d_termBBStrategies [ kind::BITVECTOR_ROTATE_LEFT ] = DefaultRotateLeftBB;
}
-
+
bool Bitblaster::hasBBAtom(TNode atom) const {
return d_bitblastedAtoms.find(atom) != d_bitblastedAtoms.end();
}
void Bitblaster::cacheTermDef(TNode term, Bits def) {
Assert (d_termCache.find(term) == d_termCache.end());
- d_termCache[term] = def;
+ d_termCache[term] = def;
}
bool Bitblaster::hasBBTerm(TNode node) const {
- return d_termCache.find(node) != d_termCache.end();
+ return d_termCache.find(node) != d_termCache.end();
}
void Bitblaster::getBBTerm(TNode node, Bits& bits) const {
- Assert (hasBBTerm(node));
+ Assert (hasBBTerm(node));
// copy?
bits = d_termCache.find(node)->second;
}
@@ -337,7 +340,7 @@ Bitblaster::Statistics::Statistics() :
d_numTermClauses("theory::bv::NumberOfTermSatClauses", 0),
d_numAtomClauses("theory::bv::NumberOfAtomSatClauses", 0),
d_numTerms("theory::bv::NumberOfBitblastedTerms", 0),
- d_numAtoms("theory::bv::NumberOfBitblastedAtoms", 0),
+ d_numAtoms("theory::bv::NumberOfBitblastedAtoms", 0),
d_bitblastTimer("theory::bv::BitblastTimer")
{
StatisticsRegistry::registerStat(&d_numTermClauses);
@@ -374,7 +377,7 @@ void Bitblaster::MinisatNotify::notify(prop::SatClause& clause) {
};
void Bitblaster::MinisatNotify::safePoint() {
- d_bv->d_out->safePoint();
+ d_bv->d_out->safePoint();
}
EqualityStatus Bitblaster::getEqualityStatus(TNode a, TNode b) {
@@ -417,70 +420,77 @@ EqualityStatus Bitblaster::getEqualityStatus(TNode a, TNode b) {
bool Bitblaster::isSharedTerm(TNode node) {
- return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
+ return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
}
bool Bitblaster::hasValue(TNode a) {
- Assert (d_termCache.find(a) != d_termCache.end());
+ Assert (d_termCache.find(a) != d_termCache.end());
Bits bits = d_termCache[a];
for (int i = bits.size() -1; i >= 0; --i) {
- SatValue bit_value;
- if (d_cnfStream->hasLiteral(bits[i])) {
+ SatValue bit_value;
+ if (d_cnfStream->hasLiteral(bits[i])) {
SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
bit_value = d_satSolver->value(bit);
if (bit_value == SAT_VALUE_UNKNOWN)
- return false;
+ return false;
} else {
- return false;
+ return false;
}
}
- return true;
+ return true;
}
-/**
+/**
* Returns the value a is currently assigned to in the SAT solver
- * or null if the value is completely unassigned.
- *
- * @param a
- *
- * @return
+ * or null if the value is completely unassigned.
+ *
+ * @param a
+ * @param fullModel whether to create a "full model," i.e., add
+ * constants to equivalence classes that don't already have them
+ *
+ * @return
*/
-Node Bitblaster::getVarValue(TNode a) {
+Node Bitblaster::getVarValue(TNode a, bool fullModel) {
if (d_termCache.find(a) == d_termCache.end()) {
Assert(isSharedTerm(a));
- return Node();
+ return Node();
}
Bits bits = d_termCache[a];
- Integer value(0);
+ Integer value(0);
for (int i = bits.size() -1; i >= 0; --i) {
SatValue bit_value;
- if (d_cnfStream->hasLiteral(bits[i])) {
+ if (d_cnfStream->hasLiteral(bits[i])) {
SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
bit_value = d_satSolver->value(bit);
- Assert (bit_value != SAT_VALUE_UNKNOWN);
+ Assert (bit_value != SAT_VALUE_UNKNOWN);
} else {
- // the bit is unconstrainted so we can give it an arbitrary value
+ //TODO: return Node() if fullModel=false?
+ // the bit is unconstrainted so we can give it an arbitrary value
bit_value = SAT_VALUE_FALSE;
}
- Integer bit_int = bit_value == SAT_VALUE_TRUE ? Integer(1) : Integer(0);
- value = value * 2 + bit_int;
+ Integer bit_int = bit_value == SAT_VALUE_TRUE ? Integer(1) : Integer(0);
+ value = value * 2 + bit_int;
}
- return utils::mkConst(BitVector(bits.size(), value));
+ return utils::mkConst(BitVector(bits.size(), value));
}
-void Bitblaster::collectModelInfo(TheoryModel* m) {
+void Bitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
__gnu_cxx::hash_set<TNode, TNodeHashFunction>::iterator it = d_variables.begin();
for (; it!= d_variables.end(); ++it) {
TNode var = *it;
if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) {
- Node const_value = getVarValue(var);
+ Node const_value = getVarValue(var, fullModel);
if(const_value == Node()) {
- // if the value is unassigned just set it to zero
- const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
+ if( fullModel ){
+ // if the value is unassigned just set it to zero
+ const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
+ }
+ }
+ if(const_value != Node()) {
+ Debug("bitvector-model") << "Bitblaster::collectModelInfo (assert (= "
+ << var << " "
+ << const_value << "))\n";
+ m->assertEquality(var, const_value, true);
}
- Debug("bitvector-model") << "Bitblaster::collectModelInfo (assert (= "
- << var << " "
- << const_value << "))\n";
- m->assertEquality(var, const_value, true);
}
}
}
diff --git a/src/theory/bv/bitblaster.h b/src/theory/bv/bitblaster.h
index c122c407d..6fab0369c 100644
--- a/src/theory/bv/bitblaster.h
+++ b/src/theory/bv/bitblaster.h
@@ -55,14 +55,14 @@ namespace bv {
typedef std::vector<Node> Bits;
-std::string toString (Bits& bits);
+std::string toString (Bits& bits);
class TheoryBV;
-/**
- * The Bitblaster that manages the mapping between Nodes
- * and their bitwise definition
- *
+/**
+ * The Bitblaster that manages the mapping between Nodes
+ * and their bitwise definition
+ *
*/
class Bitblaster {
@@ -79,26 +79,26 @@ class Bitblaster {
void notify(prop::SatClause& clause);
void safePoint();
};
-
-
+
+
typedef __gnu_cxx::hash_map <Node, Bits, TNodeHashFunction > TermDefMap;
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> AtomSet;
- typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> VarSet;
-
- typedef void (*TermBBStrategy) (TNode, Bits&, Bitblaster*);
- typedef Node (*AtomBBStrategy) (TNode, Bitblaster*);
+ typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> VarSet;
+
+ typedef void (*TermBBStrategy) (TNode, Bits&, Bitblaster*);
+ typedef Node (*AtomBBStrategy) (TNode, Bitblaster*);
TheoryBV *d_bv;
-
+
// sat solver used for bitblasting and associated CnfStream
theory::OutputChannel* d_bvOutput;
- prop::BVSatSolverInterface* d_satSolver;
+ prop::BVSatSolverInterface* d_satSolver;
prop::CnfStream* d_cnfStream;
// caches and mappings
TermDefMap d_termCache;
AtomSet d_bitblastedAtoms;
- VarSet d_variables;
+ VarSet d_variables;
context::CDList<prop::SatLiteral> d_assertedAtoms; /**< context dependent list storing the atoms
currently asserted by the DPLL SAT solver. */
@@ -111,79 +111,80 @@ class Bitblaster {
/// function tables for the various bitblasting strategies indexed by node kind
TermBBStrategy d_termBBStrategies[kind::LAST_KIND];
- AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
+ AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
// helper methods to initialize function tables
void initAtomBBStrategies();
- void initTermBBStrategies();
+ void initTermBBStrategies();
// returns a node that might be easier to bitblast
- Node bbOptimize(TNode node);
-
- void addAtom(TNode atom);
+ Node bbOptimize(TNode node);
+
+ void addAtom(TNode atom);
// division is bitblasted in terms of constraints
// so it needs to use private bitblaster interface
void bbUdiv(TNode node, Bits& bits);
void bbUrem(TNode node, Bits& bits);
- bool hasValue(TNode a);
+ bool hasValue(TNode a);
public:
void cacheTermDef(TNode node, Bits def); // public so we can cache remainder for division
void bbTerm(TNode node, Bits& bits);
void bbAtom(TNode node);
-
- Bitblaster(context::Context* c, bv::TheoryBV* bv);
+
+ Bitblaster(context::Context* c, bv::TheoryBV* bv);
~Bitblaster();
bool assertToSat(TNode node, bool propagate = true);
bool propagate();
bool solve(bool quick_solve = false);
- void getConflict(std::vector<TNode>& conflict);
+ void getConflict(std::vector<TNode>& conflict);
void explain(TNode atom, std::vector<TNode>& explanation);
EqualityStatus getEqualityStatus(TNode a, TNode b);
- /**
+ /**
* Return a constant Node representing the value of a variable
- * in the current model.
- * @param a
- *
- * @return
+ * in the current model.
+ * @param a
+ *
+ * @return
*/
- Node getVarValue(TNode a);
- /**
- * Adds a constant value for each bit-blasted variable in the model.
- *
- * @param m the model
+ Node getVarValue(TNode a, bool fullModel=true);
+ /**
+ * Adds a constant value for each bit-blasted variable in the model.
+ *
+ * @param m the model
+ * @param fullModel whether to create a "full model," i.e., add
+ * constants to equivalence classes that don't already have them
*/
- void collectModelInfo(TheoryModel* m);
- /**
- * Stores the variable (or non-bv term) and its corresponding bits.
- *
- * @param var
- * @param bits
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+ /**
+ * Stores the variable (or non-bv term) and its corresponding bits.
+ *
+ * @param var
*/
void storeVariable(TNode var) {
- d_variables.insert(var);
+ d_variables.insert(var);
}
bool isSharedTerm(TNode node);
uint64_t computeAtomWeight(TNode node);
private:
-
+
class Statistics {
public:
IntStat d_numTermClauses, d_numAtomClauses;
- IntStat d_numTerms, d_numAtoms;
+ IntStat d_numTerms, d_numAtoms;
TimerStat d_bitblastTimer;
Statistics();
- ~Statistics();
- };
-
+ ~Statistics();
+ };
+
Statistics d_statistics;
};
-} /* bv namespace */
+} /* bv namespace */
} /* theory namespace */
diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h
index 8374a3f75..0b0551283 100644
--- a/src/theory/bv/bv_subtheory.h
+++ b/src/theory/bv/bv_subtheory.h
@@ -9,7 +9,7 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Algebraic solver.
+ ** \brief Algebraic solver.
**
** Algebraic solver.
**/
@@ -46,7 +46,7 @@ inline std::ostream& operator << (std::ostream& out, SubTheory subtheory) {
out << "BV_CORE_SUBTHEORY";
break;
case SUB_INEQUALITY:
- out << "BV_INEQUALITY_SUBTHEORY";
+ out << "BV_INEQUALITY_SUBTHEORY";
default:
Unreachable();
break;
@@ -55,13 +55,10 @@ inline std::ostream& operator << (std::ostream& out, SubTheory subtheory) {
}
-const bool d_useEqualityEngine = true;
-const bool d_useSatPropagation = true;
+// forward declaration
+class TheoryBV;
-// forward declaration
-class TheoryBV;
-
-typedef context::CDQueue<Node> AssertionQueue;
+typedef context::CDQueue<Node> AssertionQueue;
/**
* Abstract base class for bit-vector subtheory solvers
*
@@ -78,7 +75,7 @@ protected:
AssertionQueue d_assertionQueue;
context::CDO<uint32_t> d_assertionIndex;
public:
-
+
SubtheorySolver(context::Context* c, TheoryBV* bv) :
d_context(c),
d_bv(bv),
@@ -86,24 +83,24 @@ public:
d_assertionIndex(c, 0)
{}
virtual ~SubtheorySolver() {}
- virtual bool check(Theory::Effort e) = 0;
+ virtual bool check(Theory::Effort e) = 0;
virtual void explain(TNode literal, std::vector<TNode>& assumptions) = 0;
virtual void preRegister(TNode node) {}
virtual void propagate(Theory::Effort e) {}
- virtual void collectModelInfo(TheoryModel* m) = 0;
- virtual Node getModelValue(TNode var) = 0;
+ virtual void collectModelInfo(TheoryModel* m, bool fullModel) = 0;
+ virtual Node getModelValue(TNode var) = 0;
virtual bool isComplete() = 0;
virtual EqualityStatus getEqualityStatus(TNode a, TNode b) = 0;
- virtual void addSharedTerm(TNode node) {}
+ virtual void addSharedTerm(TNode node) {}
bool done() { return d_assertionQueue.size() == d_assertionIndex; }
TNode get() {
- Assert (!done());
+ Assert (!done());
TNode res = d_assertionQueue[d_assertionIndex];
d_assertionIndex = d_assertionIndex + 1;
- return res;
+ return res;
}
virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); }
-};
+};
}
}
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index 2308f36a3..5a0c17134 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -34,7 +34,8 @@ BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
d_bitblaster(new Bitblaster(c, bv)),
d_bitblastQueue(c),
d_statistics(),
- d_validModelCache(c, true)
+ d_validModelCache(c, true),
+ d_useSatPropagation(options::bvPropagate())
{}
BitblastSolver::~BitblastSolver() {
@@ -83,20 +84,20 @@ void BitblastSolver::bitblastQueue() {
}
bool BitblastSolver::check(Theory::Effort e) {
- Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
+ Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n";
Assert(!options::bitvectorEagerBitblast());
- ++(d_statistics.d_numCallstoCheck);
+ ++(d_statistics.d_numCallstoCheck);
//// Lazy bit-blasting
// bit-blast enqueued nodes
bitblastQueue();
- // Processing assertions
+ // Processing assertions
while (!done()) {
TNode fact = get();
d_validModelCache = false;
- Debug("bv-bitblast") << " fact " << fact << ")\n";
+ Debug("bv-bitblast") << " fact " << fact << ")\n";
if (!d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) {
// Some atoms have not been bit-blasted yet
d_bitblaster->bbAtom(fact);
@@ -143,8 +144,8 @@ EqualityStatus BitblastSolver::getEqualityStatus(TNode a, TNode b) {
return d_bitblaster->getEqualityStatus(a, b);
}
-void BitblastSolver::collectModelInfo(TheoryModel* m) {
- return d_bitblaster->collectModelInfo(m);
+void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
+ return d_bitblaster->collectModelInfo(m, fullModel);
}
Node BitblastSolver::getModelValue(TNode node)
@@ -188,5 +189,5 @@ Node BitblastSolver::getModelValueRec(TNode node)
Assert(val.isConst());
d_modelCache[node] = val;
Debug("bitvector-model") << node << " => " << val <<"\n";
- return val;
+ return val;
}
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index 819b3d62c..f1204dbdf 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -19,7 +19,6 @@
#pragma once
#include "theory/bv/bv_subtheory.h"
-#include "theory/substitutions.h"
namespace CVC4 {
namespace theory {
namespace bv {
@@ -33,20 +32,21 @@ class BitblastSolver : public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
Statistics();
- ~Statistics();
- };
+ ~Statistics();
+ };
/** Bitblaster */
Bitblaster* d_bitblaster;
/** Nodes that still need to be bit-blasted */
context::CDQueue<TNode> d_bitblastQueue;
- Statistics d_statistics;
+ Statistics d_statistics;
typedef std::hash_map<Node, Node, NodeHashFunction> NodeMap;
NodeMap d_modelCache;
context::CDO<bool> d_validModelCache;
Node getModelValueRec(TNode node);
+ bool d_useSatPropagation;
public:
BitblastSolver(context::Context* c, TheoryBV* bv);
~BitblastSolver();
@@ -55,7 +55,7 @@ public:
bool check(Theory::Effort e);
void explain(TNode literal, std::vector<TNode>& assumptions);
EqualityStatus getEqualityStatus(TNode a, TNode b);
- void collectModelInfo(TheoryModel* m);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
Node getModelValue(TNode node);
bool isComplete() { return true; }
void bitblastQueue();
diff --git a/src/theory/bv/bv_subtheory_core.cpp b/src/theory/bv/bv_subtheory_core.cpp
index c0546f892..45946b8c8 100644
--- a/src/theory/bv/bv_subtheory_core.cpp
+++ b/src/theory/bv/bv_subtheory_core.cpp
@@ -37,53 +37,48 @@ CoreSolver::CoreSolver(context::Context* c, TheoryBV* bv)
d_isCoreTheory(c, true),
d_reasons(c)
{
- if (d_useEqualityEngine) {
-
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_CONCAT, true);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_AND);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_OR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XOR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NAND);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XNOR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_COMP);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_MULT, true);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_PLUS, true);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_EXTRACT, true);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SUB);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NEG);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UDIV);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UREM);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SDIV);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SREM);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SMOD);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SHL);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_LSHR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ASHR);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULE);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGE);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLE);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGT);
- // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGE);
- }
+
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_CONCAT, true);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_AND);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_OR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XOR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NAND);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NOR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_XNOR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_COMP);
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_MULT, true);
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_PLUS, true);
+ d_equalityEngine.addFunctionKind(kind::BITVECTOR_EXTRACT, true);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SUB);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_NEG);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UDIV);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UREM);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SDIV);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SREM);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SMOD);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SHL);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_LSHR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ASHR);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_ULE);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_UGE);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SLE);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGT);
+ // d_equalityEngine.addFunctionKind(kind::BITVECTOR_SGE);
}
CoreSolver::~CoreSolver() {
- delete d_slicer;
+ delete d_slicer;
}
void CoreSolver::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
void CoreSolver::preRegister(TNode node) {
- if (!d_useEqualityEngine)
- return;
-
if (node.getKind() == kind::EQUAL) {
d_equalityEngine.addTriggerEquality(node);
if (options::bitvectorCoreSolver()) {
@@ -109,51 +104,51 @@ Node CoreSolver::getBaseDecomposition(TNode a) {
std::vector<Node> a_decomp;
d_slicer->getBaseDecomposition(a, a_decomp);
Node new_a = utils::mkConcat(a_decomp);
- Debug("bv-slicer") << "CoreSolver::getBaseDecomposition " << a <<" => " << new_a << "\n";
- return new_a;
+ Debug("bv-slicer") << "CoreSolver::getBaseDecomposition " << a <<" => " << new_a << "\n";
+ return new_a;
}
bool CoreSolver::decomposeFact(TNode fact) {
- Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
+ Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
// assert decompositions since the equality engine does not know the semantics of
// concat:
// a == a_1 concat ... concat a_k
// b == b_1 concat ... concat b_k
- Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
- // FIXME: are this the right things to assert?
+ Debug("bv-slicer") << "CoreSolver::decomposeFact fact=" << fact << endl;
+ // FIXME: are this the right things to assert?
// assert decompositions since the equality engine does not know the semantics of
// concat:
// a == a_1 concat ... concat a_k
// b == b_1 concat ... concat b_k
- TNode eq = fact.getKind() == kind::NOT? fact[0] : fact;
+ TNode eq = fact.getKind() == kind::NOT? fact[0] : fact;
TNode a = eq[0];
TNode b = eq[1];
Node new_a = getBaseDecomposition(a);
- Node new_b = getBaseDecomposition(b);
-
+ Node new_b = getBaseDecomposition(b);
+
Assert (utils::getSize(new_a) == utils::getSize(new_b) &&
- utils::getSize(new_a) == utils::getSize(a));
-
+ utils::getSize(new_a) == utils::getSize(a));
+
NodeManager* nm = NodeManager::currentNM();
Node a_eq_new_a = nm->mkNode(kind::EQUAL, a, new_a);
Node b_eq_new_b = nm->mkNode(kind::EQUAL, b, new_b);
bool ok = true;
ok = assertFactToEqualityEngine(a_eq_new_a, utils::mkTrue());
- if (!ok) return false;
+ if (!ok) return false;
ok = assertFactToEqualityEngine(b_eq_new_b, utils::mkTrue());
- if (!ok) return false;
+ if (!ok) return false;
ok = assertFactToEqualityEngine(fact, fact);
if (!ok) return false;
-
+
if (fact.getKind() == kind::EQUAL) {
// assert the individual equalities as well
// a_i == b_i
if (new_a.getKind() == kind::BITVECTOR_CONCAT &&
new_b.getKind() == kind::BITVECTOR_CONCAT) {
-
- Assert (new_a.getNumChildren() == new_b.getNumChildren());
+
+ Assert (new_a.getNumChildren() == new_b.getNumChildren());
for (unsigned i = 0; i < new_a.getNumChildren(); ++i) {
Node eq_i = nm->mkNode(kind::EQUAL, new_a[i], new_b[i]);
ok = assertFactToEqualityEngine(eq_i, fact);
@@ -161,23 +156,23 @@ bool CoreSolver::decomposeFact(TNode fact) {
}
}
}
- return true;
+ return true;
}
bool CoreSolver::check(Theory::Effort e) {
Trace("bitvector::core") << "CoreSolver::check \n";
Assert (!d_bv->inConflict());
- ++(d_statistics.d_numCallstoCheck);
- bool ok = true;
+ ++(d_statistics.d_numCallstoCheck);
+ bool ok = true;
std::vector<Node> core_eqs;
while (! done()) {
- TNode fact = get();
-
+ TNode fact = get();
+
// update whether we are in the core fragment
if (d_isCoreTheory && !d_slicer->isCoreTerm(fact)) {
- d_isCoreTheory = false;
+ d_isCoreTheory = false;
}
-
+
// only reason about equalities
if (fact.getKind() == kind::EQUAL || (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL)) {
if (options::bitvectorCoreSolver()) {
@@ -186,31 +181,31 @@ bool CoreSolver::check(Theory::Effort e) {
ok = assertFactToEqualityEngine(fact, fact);
}
} else {
- ok = assertFactToEqualityEngine(fact, fact);
+ ok = assertFactToEqualityEngine(fact, fact);
}
if (!ok)
- return false;
+ return false;
}
-
+
if (Theory::fullEffort(e) && isComplete()) {
buildModel();
}
-
+
return true;
}
void CoreSolver::buildModel() {
if (options::bitvectorCoreSolver()) {
// FIXME
- Unreachable();
- return;
+ Unreachable();
+ return;
}
- Debug("bv-core") << "CoreSolver::buildModel() \n";
- d_modelValues.clear();
+ Debug("bv-core") << "CoreSolver::buildModel() \n";
+ d_modelValues.clear();
TNodeSet constants;
- TNodeSet constants_in_eq_engine;
+ TNodeSet constants_in_eq_engine;
// collect constants in equality engine
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
while (!eqcs_i.isFinished()) {
TNode repr = *eqcs_i;
if (repr.getKind() == kind::CONST_BITVECTOR) {
@@ -218,39 +213,39 @@ void CoreSolver::buildModel() {
eq::EqClassIterator it(repr, &d_equalityEngine);
if (!(++it).isFinished() || true) {
constants.insert(repr);
- constants_in_eq_engine.insert(repr);
+ constants_in_eq_engine.insert(repr);
}
}
- ++eqcs_i;
+ ++eqcs_i;
}
// build repr to value map
-
+
eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
while (!eqcs_i.isFinished()) {
TNode repr = *eqcs_i;
++eqcs_i;
-
+
if (repr.getKind() != kind::VARIABLE &&
repr.getKind() != kind::SKOLEM &&
repr.getKind() != kind::CONST_BITVECTOR &&
!d_bv->isSharedTerm(repr)) {
- continue;
+ continue;
}
-
- TypeNode type = repr.getType();
+
+ TypeNode type = repr.getType();
if (type.isBitVector() && repr.getKind()!= kind::CONST_BITVECTOR) {
- Debug("bv-core-model") << " processing " << repr <<"\n";
+ Debug("bv-core-model") << " processing " << repr <<"\n";
// we need to assign a value for it
TypeEnumerator te(type);
- Node val;
+ Node val;
do {
- val = *te;
+ val = *te;
++te;
// Debug("bv-core-model") << " trying value " << val << "\n";
// Debug("bv-core-model") << " is in set? " << constants.count(val) << "\n";
- // Debug("bv-core-model") << " enumerator done? " << te.isFinished() << "\n";
+ // Debug("bv-core-model") << " enumerator done? " << te.isFinished() << "\n";
} while (constants.count(val) != 0 && !(te.isFinished()));
-
+
if (te.isFinished() && constants.count(val) != 0) {
// if we cannot enumerate anymore values we just return the lemma stating that
// at least two of the representatives are equal.
@@ -259,15 +254,15 @@ void CoreSolver::buildModel() {
for (TNodeSet::const_iterator it = constants_in_eq_engine.begin();
it != constants_in_eq_engine.end(); ++it) {
- TNode constant = *it;
+ TNode constant = *it;
if (utils::getSize(constant) == utils::getSize(repr)) {
- representatives.push_back(constant);
+ representatives.push_back(constant);
}
}
for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
representatives.push_back(it->first);
}
- std::vector<Node> equalities;
+ std::vector<Node> equalities;
for (unsigned i = 0; i < representatives.size(); ++i) {
for (unsigned j = i + 1; j < representatives.size(); ++j) {
TNode a = representatives[i];
@@ -279,19 +274,19 @@ void CoreSolver::buildModel() {
}
Node lemma = utils::mkOr(equalities);
d_bv->lemma(lemma);
- Debug("bv-core") << " lemma: " << lemma << "\n";
- return;
+ Debug("bv-core") << " lemma: " << lemma << "\n";
+ return;
}
Debug("bv-core-model") << " " << repr << " => " << val <<"\n" ;
constants.insert(val);
- d_modelValues[repr] = val;
+ d_modelValues[repr] = val;
}
}
}
bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) {
- // Notify the equality engine
- if (d_useEqualityEngine && !d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || !d_bv->getPropagatingSubtheory(fact) == SUB_CORE)) {
+ // Notify the equality engine
+ if (!d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || !d_bv->getPropagatingSubtheory(fact) == SUB_CORE)) {
Debug("bv-slicer-eq") << "CoreSolver::assertFactToEqualityEngine fact=" << fact << endl;
// Debug("bv-slicer-eq") << " reason=" << reason << endl;
bool negated = fact.getKind() == kind::NOT;
@@ -315,8 +310,8 @@ bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) {
// checking for a conflict
if (d_bv->inConflict()) {
return false;
- }
- return true;
+ }
+ return true;
}
bool CoreSolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value) {
@@ -361,10 +356,10 @@ void CoreSolver::conflict(TNode a, TNode b) {
d_bv->setConflict(conflict);
}
-void CoreSolver::collectModelInfo(TheoryModel* m) {
+void CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
if (options::bitvectorCoreSolver()) {
Unreachable();
- return;
+ return;
}
if (Debug.isOn("bitvector-model")) {
context::CDQueue<Node>::const_iterator it = d_assertionQueue.begin();
@@ -377,11 +372,11 @@ void CoreSolver::collectModelInfo(TheoryModel* m) {
d_bv->computeRelevantTerms(termSet);
m->assertEqualityEngine(&d_equalityEngine, &termSet);
if (isComplete()) {
- Debug("bitvector-model") << "CoreSolver::collectModelInfo complete.";
+ Debug("bitvector-model") << "CoreSolver::collectModelInfo complete.";
for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
Node a = it->first;
Node b = it->second;
- m->assertEquality(a, b, true);
+ m->assertEquality(a, b, true);
}
}
}
@@ -390,23 +385,23 @@ Node CoreSolver::getModelValue(TNode var) {
// we don't need to evaluate bv expressions and only look at variable values
// because this only gets called when the core theory is complete (i.e. no other bv
// function symbols are currently asserted)
- Assert (d_slicer->isCoreTerm(var));
-
- Debug("bitvector-model") << "CoreSolver::getModelValue (" << var <<")";
+ Assert (d_slicer->isCoreTerm(var));
+
+ Debug("bitvector-model") << "CoreSolver::getModelValue (" << var <<")";
Assert (isComplete());
TNode repr = d_equalityEngine.getRepresentative(var);
- Node result = Node();
+ Node result = Node();
if (repr.getKind() == kind::CONST_BITVECTOR) {
- result = repr;
+ result = repr;
} else if (d_modelValues.find(repr) == d_modelValues.end()) {
// it may be a shared term that never gets asserted
// result is just Null
Assert(d_bv->isSharedTerm(var));
} else {
- result = d_modelValues[repr];
+ result = d_modelValues[repr];
}
- Debug("bitvector-model") << " => " << result <<"\n";
- return result;
+ Debug("bitvector-model") << " => " << result <<"\n";
+ return result;
}
CoreSolver::Statistics::Statistics()
diff --git a/src/theory/bv/bv_subtheory_core.h b/src/theory/bv/bv_subtheory_core.h
index 423408a7c..b886bbdd5 100644
--- a/src/theory/bv/bv_subtheory_core.h
+++ b/src/theory/bv/bv_subtheory_core.h
@@ -25,21 +25,21 @@ namespace CVC4 {
namespace theory {
namespace bv {
-class Slicer;
-class Base;
+class Slicer;
+class Base;
/**
* Bitvector equality solver
*/
class CoreSolver : public SubtheorySolver {
typedef __gnu_cxx::hash_map<TNode, Node, TNodeHashFunction> ModelValue;
- typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+ typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
struct Statistics {
IntStat d_numCallstoCheck;
Statistics();
- ~Statistics();
- };
-
+ ~Statistics();
+ };
+
// NotifyClass: handles call-back from congruence closure module
class NotifyClass : public eq::EqualityEngineNotify {
CoreSolver& d_solver;
@@ -59,13 +59,13 @@ class CoreSolver : public SubtheorySolver {
/** The notify class for d_equalityEngine */
NotifyClass d_notify;
-
+
/** Equality engine */
eq::EqualityEngine d_equalityEngine;
/** Store a propagation to the bv solver */
bool storePropagation(TNode literal);
-
+
/** Store a conflict from merging two constants */
void conflict(TNode a, TNode b);
@@ -74,12 +74,12 @@ class CoreSolver : public SubtheorySolver {
/** To make sure we keep the explanations */
context::CDHashSet<Node, NodeHashFunction> d_reasons;
ModelValue d_modelValues;
- void buildModel();
- bool assertFactToEqualityEngine(TNode fact, TNode reason);
+ void buildModel();
+ bool assertFactToEqualityEngine(TNode fact, TNode reason);
bool decomposeFact(TNode fact);
Node getBaseDecomposition(TNode a);
- Statistics d_statistics;
-public:
+ Statistics d_statistics;
+public:
CoreSolver(context::Context* c, TheoryBV* bv);
~CoreSolver();
bool isComplete() { return d_isCoreTheory; }
@@ -87,8 +87,8 @@ public:
void preRegister(TNode node);
bool check(Theory::Effort e);
void explain(TNode literal, std::vector<TNode>& assumptions);
- void collectModelInfo(TheoryModel* m);
- Node getModelValue(TNode var);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+ Node getModelValue(TNode var);
void addSharedTerm(TNode t) {
d_equalityEngine.addTriggerTerm(t, THEORY_BV);
}
diff --git a/src/theory/bv/bv_subtheory_inequality.cpp b/src/theory/bv/bv_subtheory_inequality.cpp
index f45250f5b..a3970c9e3 100644
--- a/src/theory/bv/bv_subtheory_inequality.cpp
+++ b/src/theory/bv/bv_subtheory_inequality.cpp
@@ -29,17 +29,17 @@ using namespace CVC4::theory::bv::utils;
bool InequalitySolver::check(Theory::Effort e) {
Debug("bv-subtheory-inequality") << "InequalitySolveR::check("<< e <<")\n";
++(d_statistics.d_numCallstoCheck);
-
- bool ok = true;
+
+ bool ok = true;
while (!done() && ok) {
TNode fact = get();
- Debug("bv-subtheory-inequality") << " "<< fact <<"\n";
+ Debug("bv-subtheory-inequality") << " "<< fact <<"\n";
if (fact.getKind() == kind::EQUAL) {
TNode a = fact[0];
TNode b = fact[1];
ok = d_inequalityGraph.addInequality(a, b, false, fact);
if (ok)
- ok = d_inequalityGraph.addInequality(b, a, false, fact);
+ ok = d_inequalityGraph.addInequality(b, a, false, fact);
} else if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL) {
TNode a = fact[0][0];
TNode b = fact[0][1];
@@ -47,40 +47,40 @@ bool InequalitySolver::check(Theory::Effort e) {
}
if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::BITVECTOR_ULE) {
TNode a = fact[0][1];
- TNode b = fact[0][0];
+ TNode b = fact[0][0];
ok = d_inequalityGraph.addInequality(a, b, true, fact);
// propagate
// if (d_bv->isSharedTerm(a) && d_bv->isSharedTerm(b)) {
- // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
+ // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
// d_bv->storePropagation(neq, SUB_INEQUALITY);
// d_explanations[neq] = fact;
// }
} else if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::BITVECTOR_ULT) {
TNode a = fact[0][1];
- TNode b = fact[0][0];
+ TNode b = fact[0][0];
ok = d_inequalityGraph.addInequality(a, b, false, fact);
} else if (fact.getKind() == kind::BITVECTOR_ULT) {
TNode a = fact[0];
- TNode b = fact[1];
+ TNode b = fact[1];
ok = d_inequalityGraph.addInequality(a, b, true, fact);
// propagate
// if (d_bv->isSharedTerm(a) && d_bv->isSharedTerm(b)) {
- // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
+ // Node neq = utils::mkNode(kind::NOT, utils::mkNode(kind::EQUAL, a, b));
// d_bv->storePropagation(neq, SUB_INEQUALITY);
// d_explanations[neq] = fact;
// }
} else if (fact.getKind() == kind::BITVECTOR_ULE) {
TNode a = fact[0];
- TNode b = fact[1];
+ TNode b = fact[1];
ok = d_inequalityGraph.addInequality(a, b, false, fact);
}
}
-
+
if (!ok) {
std::vector<TNode> conflict;
- d_inequalityGraph.getConflict(conflict);
+ d_inequalityGraph.getConflict(conflict);
d_bv->setConflict(utils::flattenAnd(conflict));
- return false;
+ return false;
}
if (isComplete() && Theory::fullEffort(e)) {
@@ -89,36 +89,39 @@ bool InequalitySolver::check(Theory::Effort e) {
std::vector<Node> lemmas;
d_inequalityGraph.checkDisequalities(lemmas);
for(unsigned i = 0; i < lemmas.size(); ++i) {
- d_bv->lemma(lemmas[i]);
+ d_bv->lemma(lemmas[i]);
}
}
- return true;
+ return true;
}
EqualityStatus InequalitySolver::getEqualityStatus(TNode a, TNode b) {
+ if (!isComplete())
+ return EQUALITY_UNKNOWN;
+
Node a_lt_b = utils::mkNode(kind::BITVECTOR_ULT, a, b);
Node b_lt_a = utils::mkNode(kind::BITVECTOR_ULT, b, a);
// if an inequality containing the terms has been asserted then we know
// the equality is false
if (d_assertionSet.contains(a_lt_b) || d_assertionSet.contains(b_lt_a)) {
- return EQUALITY_FALSE;
+ return EQUALITY_FALSE;
}
-
+
if (!d_inequalityGraph.hasValueInModel(a) ||
!d_inequalityGraph.hasValueInModel(b)) {
- return EQUALITY_UNKNOWN;
+ return EQUALITY_UNKNOWN;
}
// TODO: check if this disequality is entailed by inequalities via transitivity
-
+
BitVector a_val = d_inequalityGraph.getValueInModel(a);
BitVector b_val = d_inequalityGraph.getValueInModel(b);
-
+
if (a_val == b_val) {
- return EQUALITY_TRUE_IN_MODEL;
+ return EQUALITY_TRUE_IN_MODEL;
} else {
- return EQUALITY_FALSE_IN_MODEL;
+ return EQUALITY_FALSE_IN_MODEL;
}
}
@@ -126,19 +129,19 @@ void InequalitySolver::assertFact(TNode fact) {
d_assertionQueue.push_back(fact);
d_assertionSet.insert(fact);
if (!isInequalityOnly(fact)) {
- d_isComplete = false;
+ d_isComplete = false;
}
}
bool InequalitySolver::isInequalityOnly(TNode node) {
if (d_ineqTermCache.find(node) != d_ineqTermCache.end()) {
- return d_ineqTermCache[node];
+ return d_ineqTermCache[node];
}
-
+
if (node.getKind() == kind::NOT) {
- node = node[0];
+ node = node[0];
}
-
+
if (node.getKind() != kind::EQUAL &&
node.getKind() != kind::BITVECTOR_ULT &&
node.getKind() != kind::BITVECTOR_ULE &&
@@ -146,50 +149,50 @@ bool InequalitySolver::isInequalityOnly(TNode node) {
node.getKind() != kind::SELECT &&
node.getKind() != kind::STORE &&
node.getMetaKind() != kind::metakind::VARIABLE) {
- return false;
+ return false;
}
- bool res = true;
+ bool res = true;
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
res = res && isInequalityOnly(node[i]);
}
- d_ineqTermCache[node] = res;
- return res;
+ d_ineqTermCache[node] = res;
+ return res;
}
void InequalitySolver::explain(TNode literal, std::vector<TNode>& assumptions) {
Assert (d_explanations.find(literal) != d_explanations.end());
TNode explanation = d_explanations[literal];
assumptions.push_back(explanation);
- Debug("bv-inequality-explain") << "InequalitySolver::explain " << literal << " with " << explanation <<"\n";
+ Debug("bv-inequality-explain") << "InequalitySolver::explain " << literal << " with " << explanation <<"\n";
}
void InequalitySolver::propagate(Theory::Effort e) {
- Assert (false);
+ Assert (false);
}
-void InequalitySolver::collectModelInfo(TheoryModel* m) {
- Debug("bitvector-model") << "InequalitySolver::collectModelInfo \n";
+void InequalitySolver::collectModelInfo(TheoryModel* m, bool fullModel) {
+ Debug("bitvector-model") << "InequalitySolver::collectModelInfo \n";
std::vector<Node> model;
d_inequalityGraph.getAllValuesInModel(model);
for (unsigned i = 0; i < model.size(); ++i) {
- Assert (model[i].getKind() == kind::EQUAL);
- m->assertEquality(model[i][0], model[i][1], true);
+ Assert (model[i].getKind() == kind::EQUAL);
+ m->assertEquality(model[i][0], model[i][1], true);
}
}
Node InequalitySolver::getModelValue(TNode var) {
- Assert (isInequalityOnly(var));
- Debug("bitvector-model") << "InequalitySolver::getModelValue (" << var <<")";
+ Assert (isInequalityOnly(var));
+ Debug("bitvector-model") << "InequalitySolver::getModelValue (" << var <<")";
Assert (isComplete());
- Node result = Node();
+ Node result = Node();
if (!d_inequalityGraph.hasValueInModel(var)) {
Assert (d_bv->isSharedTerm(var));
} else {
BitVector val = d_inequalityGraph.getValueInModel(var);
result = utils::mkConst(val);
}
- Debug("bitvector-model") << " => " << result <<"\n";
- return result;
+ Debug("bitvector-model") << " => " << result <<"\n";
+ return result;
}
InequalitySolver::Statistics::Statistics()
diff --git a/src/theory/bv/bv_subtheory_inequality.h b/src/theory/bv/bv_subtheory_inequality.h
index 390a329ff..6e0139e09 100644
--- a/src/theory/bv/bv_subtheory_inequality.h
+++ b/src/theory/bv/bv_subtheory_inequality.h
@@ -9,7 +9,7 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Algebraic solver.
+ ** \brief Algebraic solver.
**
** Algebraic solver.
**/
@@ -31,16 +31,16 @@ class InequalitySolver: public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
Statistics();
- ~Statistics();
- };
+ ~Statistics();
+ };
- context::CDHashSet<Node, NodeHashFunction> d_assertionSet;
+ context::CDHashSet<Node, NodeHashFunction> d_assertionSet;
InequalityGraph d_inequalityGraph;
- context::CDHashMap<Node, TNode, NodeHashFunction> d_explanations;
+ context::CDHashMap<Node, TNode, NodeHashFunction> d_explanations;
context::CDO<bool> d_isComplete;
- __gnu_cxx::hash_map<TNode, bool, TNodeHashFunction> d_ineqTermCache;
- bool isInequalityOnly(TNode node);
- Statistics d_statistics;
+ __gnu_cxx::hash_map<TNode, bool, TNodeHashFunction> d_ineqTermCache;
+ bool isInequalityOnly(TNode node);
+ Statistics d_statistics;
public:
InequalitySolver(context::Context* c, TheoryBV* bv)
: SubtheorySolver(c, bv),
@@ -51,19 +51,19 @@ public:
d_ineqTermCache(),
d_statistics()
{}
-
+
bool check(Theory::Effort e);
- void propagate(Theory::Effort e);
+ void propagate(Theory::Effort e);
void explain(TNode literal, std::vector<TNode>& assumptions);
bool isComplete() { return d_isComplete; }
- void collectModelInfo(TheoryModel* m);
- Node getModelValue(TNode var);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+ Node getModelValue(TNode var);
EqualityStatus getEqualityStatus(TNode a, TNode b);
- void assertFact(TNode fact);
-};
+ void assertFact(TNode fact);
+};
}
}
}
-#endif /* __CVC4__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H */
+#endif /* __CVC4__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H */
diff --git a/src/theory/bv/kinds b/src/theory/bv/kinds
index 052e477ea..aeae1073e 100644
--- a/src/theory/bv/kinds
+++ b/src/theory/bv/kinds
@@ -120,6 +120,14 @@ parameterized BITVECTOR_SIGN_EXTEND BITVECTOR_SIGN_EXTEND_OP 1 "bit-vector sign-
parameterized BITVECTOR_ROTATE_LEFT BITVECTOR_ROTATE_LEFT_OP 1 "bit-vector rotate left"
parameterized BITVECTOR_ROTATE_RIGHT BITVECTOR_ROTATE_RIGHT_OP 1 "bit-vector rotate right"
+constant INT_TO_BITVECTOR_OP \
+ ::CVC4::IntToBitVector \
+ "::CVC4::UnsignedHashFunction< ::CVC4::IntToBitVector >" \
+ "util/bitvector.h" \
+ "operator for the integer conversion to bit-vector"
+parameterized INT_TO_BITVECTOR INT_TO_BITVECTOR_OP 1 "integer conversion to bit-vector"
+operator BITVECTOR_TO_NAT 1 "bit-vector conversion to (nonnegative) integer"
+
typerule CONST_BITVECTOR ::CVC4::theory::bv::BitVectorConstantTypeRule
typerule BITVECTOR_AND ::CVC4::theory::bv::BitVectorFixedWidthTypeRule
@@ -166,4 +174,7 @@ typerule BITVECTOR_REPEAT ::CVC4::theory::bv::BitVectorRepeatTypeRule
typerule BITVECTOR_ZERO_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule
typerule BITVECTOR_SIGN_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule
+typerule BITVECTOR_TO_NAT ::CVC4::theory::bv::BitVectorConversionTypeRule
+typerule INT_TO_BITVECTOR ::CVC4::theory::bv::BitVectorConversionTypeRule
+
endtheory
diff --git a/src/theory/bv/options b/src/theory/bv/options
index 7b87baa21..077299d1f 100644
--- a/src/theory/bv/options
+++ b/src/theory/bv/options
@@ -22,5 +22,11 @@ option bitvectorCoreSolver --bv-core-solver bool
option bvToBool --bv-to-bool bool
lift bit-vectors of size 1 to booleans when possible
+
+option bvPropagate --bv-propagate bool :default true
+ use bit-vector propagation in the bit-blaster
+
+option bvEquality --bv-eq bool :default true
+ use the equality engine for the bit-vector theory
endmodule
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index cb68a0f65..a2de951aa 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -49,29 +49,32 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel&
d_literalsToPropagateIndex(c, 0),
d_propagatedBy(c)
{
- SubtheorySolver* core_solver = new CoreSolver(c, this);
- d_subtheories.push_back(core_solver);
- d_subtheoryMap[SUB_CORE] = core_solver;
-
+ if (options::bvEquality()) {
+ SubtheorySolver* core_solver = new CoreSolver(c, this);
+ d_subtheories.push_back(core_solver);
+ d_subtheoryMap[SUB_CORE] = core_solver;
+ }
if (options::bitvectorInequalitySolver()) {
- SubtheorySolver* ineq_solver = new InequalitySolver(c, this);
+ SubtheorySolver* ineq_solver = new InequalitySolver(c, this);
d_subtheories.push_back(ineq_solver);
d_subtheoryMap[SUB_INEQUALITY] = ineq_solver;
}
-
- SubtheorySolver* bb_solver = new BitblastSolver(c, this);
+
+ SubtheorySolver* bb_solver = new BitblastSolver(c, this);
d_subtheories.push_back(bb_solver);
d_subtheoryMap[SUB_BITBLAST] = bb_solver;
}
TheoryBV::~TheoryBV() {
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- delete d_subtheories[i];
+ delete d_subtheories[i];
}
}
void TheoryBV::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
+ if (options::bvEquality()) {
+ dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
+ }
}
TheoryBV::Statistics::Statistics():
@@ -110,7 +113,7 @@ void TheoryBV::preRegisterTerm(TNode node) {
return;
}
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->preRegister(node);
+ d_subtheories[i]->preRegister(node);
}
}
@@ -131,22 +134,22 @@ void TheoryBV::checkForLemma(TNode fact) {
if (fact[0].getKind() == kind::BITVECTOR_UREM_TOTAL) {
TNode urem = fact[0];
TNode result = fact[1];
- TNode divisor = urem[1];
+ TNode divisor = urem[1];
Node result_ult_div = mkNode(kind::BITVECTOR_ULT, result, divisor);
Node divisor_eq_0 = mkNode(kind::EQUAL,
divisor,
- mkConst(BitVector(getSize(divisor), 0u)));
+ mkConst(BitVector(getSize(divisor), 0u)));
Node split = utils::mkNode(kind::OR, divisor_eq_0, mkNode(kind::NOT, fact), result_ult_div);
lemma(split);
}
if (fact[1].getKind() == kind::BITVECTOR_UREM_TOTAL) {
TNode urem = fact[1];
TNode result = fact[0];
- TNode divisor = urem[1];
+ TNode divisor = urem[1];
Node result_ult_div = mkNode(kind::BITVECTOR_ULT, result, divisor);
Node divisor_eq_0 = mkNode(kind::EQUAL,
divisor,
- mkConst(BitVector(getSize(divisor), 0u)));
+ mkConst(BitVector(getSize(divisor), 0u)));
Node split = utils::mkNode(kind::OR, divisor_eq_0, mkNode(kind::NOT, fact), result_ult_div);
lemma(split);
}
@@ -162,9 +165,9 @@ void TheoryBV::check(Effort e)
}
if (Theory::fullEffort(e)) {
- ++(d_statistics.d_numCallsToCheckFullEffort);
+ ++(d_statistics.d_numCallsToCheckFullEffort);
} else {
- ++(d_statistics.d_numCallsToCheckStandardEffort);
+ ++(d_statistics.d_numCallsToCheckStandardEffort);
}
// if we are already in conflict just return the conflict
if (inConflict()) {
@@ -174,28 +177,29 @@ void TheoryBV::check(Effort e)
while (!done()) {
TNode fact = get().assertion;
- checkForLemma(fact);
+ checkForLemma(fact);
+
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->assertFact(fact);
+ d_subtheories[i]->assertFact(fact);
}
}
bool ok = true;
bool complete = false;
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- Assert (!inConflict());
+ Assert (!inConflict());
ok = d_subtheories[i]->check(e);
- complete = d_subtheories[i]->isComplete();
+ complete = d_subtheories[i]->isComplete();
if (!ok) {
// if we are in a conflict no need to check with other theories
Assert (inConflict());
sendConflict();
- return;
+ return;
}
if (complete) {
// if the last subtheory was complete we stop
- return;
+ return;
}
}
}
@@ -205,8 +209,8 @@ void TheoryBV::collectModelInfo( TheoryModel* m, bool fullModel ){
// Assert (fullModel); // can only query full model
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
if (d_subtheories[i]->isComplete()) {
- d_subtheories[i]->collectModelInfo(m);
- return;
+ d_subtheories[i]->collectModelInfo(m, fullModel);
+ return;
}
}
}
@@ -215,10 +219,10 @@ Node TheoryBV::getModelValue(TNode var) {
Assert(!inConflict());
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
if (d_subtheories[i]->isComplete()) {
- return d_subtheories[i]->getModelValue(var);
+ return d_subtheories[i]->getModelValue(var);
}
}
- Unreachable();
+ Unreachable();
}
void TheoryBV::propagate(Effort e) {
@@ -236,7 +240,7 @@ void TheoryBV::propagate(Effort e) {
bool ok = true;
for (; d_literalsToPropagateIndex < d_literalsToPropagate.size() && ok; d_literalsToPropagateIndex = d_literalsToPropagateIndex + 1) {
TNode literal = d_literalsToPropagate[d_literalsToPropagateIndex];
- // temporary fix for incremental bit-blasting
+ // temporary fix for incremental bit-blasting
if (d_valuation.isSatLiteral(literal)) {
Debug("bitvector::propagate") << "TheoryBV:: propagating " << literal <<"\n";
ok = d_out->propagate(literal);
@@ -286,14 +290,14 @@ Node TheoryBV::ppRewrite(TNode t)
if (options::bitvectorCoreSolver() && t.getKind() == kind::EQUAL) {
std::vector<Node> equalities;
Slicer::splitEqualities(t, equalities);
- return utils::mkAnd(equalities);
+ return utils::mkAnd(equalities);
}
-
+
return t;
}
void TheoryBV::presolve() {
- Debug("bitvector") << "TheoryBV::presolve" << endl;
+ Debug("bitvector") << "TheoryBV::presolve" << endl;
}
bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
@@ -318,7 +322,7 @@ bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
// Safe to ignore this one, subtheory should produce a conflict
return true;
}
-
+
d_propagatedBy[literal] = subtheory;
}
@@ -366,7 +370,7 @@ Node TheoryBV::explain(TNode node) {
void TheoryBV::addSharedTerm(TNode t) {
Debug("bitvector::sharing") << indent() << "TheoryBV::addSharedTerm(" << t << ")" << std::endl;
d_sharedTermsSet.insert(t);
- if (!options::bitvectorEagerBitblast() && d_useEqualityEngine) {
+ if (!options::bitvectorEagerBitblast() && options::bvEquality()) {
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
d_subtheories[i]->addSharedTerm(t);
}
@@ -379,11 +383,11 @@ EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
if (options::bitvectorEagerBitblast()) {
return EQUALITY_UNKNOWN;
}
-
+
for (unsigned i = 0; i < d_subtheories.size(); ++i) {
EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
if (status != EQUALITY_UNKNOWN) {
- return status;
+ return status;
}
}
return EQUALITY_UNKNOWN; ;
diff --git a/src/theory/bv/theory_bv_rewrite_rules.h b/src/theory/bv/theory_bv_rewrite_rules.h
index baaf7e133..8426afb59 100644
--- a/src/theory/bv/theory_bv_rewrite_rules.h
+++ b/src/theory/bv/theory_bv_rewrite_rules.h
@@ -66,6 +66,9 @@ enum RewriteRuleId {
SremEliminate,
ZeroExtendEliminate,
SignExtendEliminate,
+ BVToNatEliminate,
+ IntToBVEliminate,
+
/// ground term evaluation
EvalEquals,
EvalConcat,
@@ -173,13 +176,15 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case FailEq: out << "FailEq"; return out;
case SimplifyEq: out << "SimplifyEq"; return out;
case ReflexivityEq: out << "ReflexivityEq"; return out;
- case UgtEliminate: out << "UgtEliminate"; return out;
- case SgtEliminate: out << "SgtEliminate"; return out;
- case UgeEliminate: out << "UgeEliminate"; return out;
- case SgeEliminate: out << "SgeEliminate"; return out;
+ case UgtEliminate: out << "UgtEliminate"; return out;
+ case SgtEliminate: out << "SgtEliminate"; return out;
+ case UgeEliminate: out << "UgeEliminate"; return out;
+ case SgeEliminate: out << "SgeEliminate"; return out;
case RepeatEliminate: out << "RepeatEliminate"; return out;
case RotateLeftEliminate: out << "RotateLeftEliminate"; return out;
case RotateRightEliminate:out << "RotateRightEliminate";return out;
+ case BVToNatEliminate: out << "BVToNatEliminate"; return out;
+ case IntToBVEliminate: out << "IntToBVEliminate"; return out;
case NandEliminate: out << "NandEliminate"; return out;
case NorEliminate : out << "NorEliminate"; return out;
case SdivEliminate : out << "SdivEliminate"; return out;
@@ -214,7 +219,7 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case ExtractBitwise : out << "ExtractBitwise"; return out;
case ExtractNot : out << "ExtractNot"; return out;
case ExtractArith : out << "ExtractArith"; return out;
- case ExtractArith2 : out << "ExtractArith2"; return out;
+ case ExtractArith2 : out << "ExtractArith2"; return out;
case DoubleNeg : out << "DoubleNeg"; return out;
case NotConcat : out << "NotConcat"; return out;
case NotAnd : out << "NotAnd"; return out;
@@ -226,7 +231,7 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case BitwiseNotOr : out << "BitwiseNotOr"; return out;
case XorNot : out << "XorNot"; return out;
case LtSelf : out << "LtSelf"; return out;
- case LteSelf : out << "LteSelf"; return out;
+ case LteSelf : out << "LteSelf"; return out;
case UltZero : out << "UltZero"; return out;
case UleZero : out << "UleZero"; return out;
case ZeroUle : out << "ZeroUle"; return out;
@@ -491,7 +496,8 @@ struct AllRewriteRules {
RewriteRule<BitwiseEq> rule113;
RewriteRule<UltOne> rule114;
RewriteRule<SltZero> rule115;
-
+ RewriteRule<BVToNatEliminate> rule116;
+ RewriteRule<IntToBVEliminate> rule117;
};
template<> inline
diff --git a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
index a5368d2c9..9f3d12415 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
@@ -198,8 +198,9 @@ Node RewriteRule<EvalNeg>::apply(TNode node) {
}
template<> inline
bool RewriteRule<EvalUdiv>::applies(TNode node) {
- return (node.getKind() == kind::BITVECTOR_UDIV_TOTAL &&
- utils::isBVGroundTerm(node));
+ return (utils::isBVGroundTerm(node) &&
+ (node.getKind() == kind::BITVECTOR_UDIV_TOTAL ||
+ (node.getKind() == kind::BITVECTOR_UDIV && node[1].isConst())));
}
template<> inline
@@ -213,8 +214,9 @@ Node RewriteRule<EvalUdiv>::apply(TNode node) {
}
template<> inline
bool RewriteRule<EvalUrem>::applies(TNode node) {
- return (node.getKind() == kind::BITVECTOR_UREM_TOTAL &&
- utils::isBVGroundTerm(node));
+ return (utils::isBVGroundTerm(node) &&
+ (node.getKind() == kind::BITVECTOR_UREM_TOTAL ||
+ (node.getKind() == kind::BITVECTOR_UREM && node[1].isConst())));
}
template<> inline
diff --git a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
index cf36633fa..b513dbf90 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
@@ -231,6 +231,57 @@ Node RewriteRule<RotateRightEliminate>::apply(TNode node) {
}
template<>
+bool RewriteRule<BVToNatEliminate>::applies(TNode node) {
+ return (node.getKind() == kind::BITVECTOR_TO_NAT);
+}
+
+template<>
+Node RewriteRule<BVToNatEliminate>::apply(TNode node) {
+ Debug("bv-rewrite") << "RewriteRule<BVToNatEliminate>(" << node << ")" << std::endl;
+
+ const unsigned size = utils::getSize(node[0]);
+ NodeManager* const nm = NodeManager::currentNM();
+ const Node z = nm->mkConst(Rational(0));
+ const Node bvone = nm->mkConst(BitVector(1u, 1u));
+
+ NodeBuilder<> result(kind::PLUS);
+ Integer i = 1;
+ for(unsigned bit = 0; bit < size; ++bit, i *= 2) {
+ Node cond = nm->mkNode(kind::EQUAL, nm->mkNode(nm->mkConst(BitVectorExtract(bit, bit)), node[0]), bvone);
+ result << nm->mkNode(kind::ITE, cond, nm->mkConst(Rational(i)), z);
+ }
+
+ return Node(result);
+}
+
+template<>
+bool RewriteRule<IntToBVEliminate>::applies(TNode node) {
+ return (node.getKind() == kind::INT_TO_BITVECTOR);
+}
+
+template<>
+Node RewriteRule<IntToBVEliminate>::apply(TNode node) {
+ Debug("bv-rewrite") << "RewriteRule<IntToBVEliminate>(" << node << ")" << std::endl;
+
+ const unsigned size = node.getOperator().getConst<IntToBitVector>().size;
+ NodeManager* const nm = NodeManager::currentNM();
+ const Node bvzero = nm->mkConst(BitVector(1u, 0u));
+ const Node bvone = nm->mkConst(BitVector(1u, 1u));
+
+ std::vector<Node> v;
+ Integer i = 2;
+ while(v.size() < size) {
+ Node cond = nm->mkNode(kind::GEQ, nm->mkNode(kind::INTS_MODULUS_TOTAL, node[0], nm->mkConst(Rational(i))), nm->mkConst(Rational(i, 2)));
+ v.push_back(nm->mkNode(kind::ITE, cond, bvone, bvzero));
+ i *= 2;
+ }
+
+ NodeBuilder<> result(kind::BITVECTOR_CONCAT);
+ result.append(v.rbegin(), v.rend());
+ return Node(result);
+}
+
+template<>
bool RewriteRule<NandEliminate>::applies(TNode node) {
return (node.getKind() == kind::BITVECTOR_NAND &&
node.getNumChildren() == 2);
diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
index d660dde29..ff7d67cb0 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
@@ -45,7 +45,9 @@ template<> inline
Node RewriteRule<ShlByConst>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<ShlByConst>(" << node << ")" << std::endl;
Integer amount = node[1].getConst<BitVector>().toInteger();
-
+ if (amount == 0) {
+ return node[0];
+ }
Node a = node[0];
uint32_t size = utils::getSize(a);
@@ -59,6 +61,7 @@ Node RewriteRule<ShlByConst>::apply(TNode node) {
Assert(amount < Integer(1).multiplyByPow2(32));
uint32_t uint32_amount = amount.toUnsignedInt();
+
Node left = utils::mkExtract(a, size - 1 - uint32_amount, 0);
Node right = utils::mkConst(BitVector(uint32_amount, Integer(0)));
return utils::mkConcat(left, right);
@@ -81,6 +84,9 @@ template<> inline
Node RewriteRule<LshrByConst>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<LshrByConst>(" << node << ")" << std::endl;
Integer amount = node[1].getConst<BitVector>().toInteger();
+ if (amount == 0) {
+ return node[0];
+ }
Node a = node[0];
uint32_t size = utils::getSize(a);
@@ -117,7 +123,10 @@ template<> inline
Node RewriteRule<AshrByConst>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<AshrByConst>(" << node << ")" << std::endl;
Integer amount = node[1].getConst<BitVector>().toInteger();
-
+ if (amount == 0) {
+ return node[0];
+ }
+
Node a = node[0];
uint32_t size = utils::getSize(a);
Node sign_bit = utils::mkExtract(a, size-1, size-1);
@@ -812,7 +821,9 @@ Node RewriteRule<UdivPow2>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<UdivPow2>(" << node << ")" << std::endl;
Node a = node[0];
unsigned power = utils::isPow2Const(node[1]) -1;
-
+ if (power == 0) {
+ return a;
+ }
Node extract = utils::mkExtract(a, utils::getSize(node) - 1, power);
Node zeros = utils::mkConst(power, 0);
diff --git a/src/theory/bv/theory_bv_rewriter.cpp b/src/theory/bv/theory_bv_rewriter.cpp
index 7844e5b92..2467ae3f1 100644
--- a/src/theory/bv/theory_bv_rewriter.cpp
+++ b/src/theory/bv/theory_bv_rewriter.cpp
@@ -70,7 +70,7 @@ RewriteResponse TheoryBVRewriter::postRewrite(TNode node) {
return res;
}
-RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool prerewrite) {
// reduce common subexpressions on both sides
Node resultNode = LinearRewriteStrategy
< RewriteRule<EvalUlt>,
@@ -82,7 +82,7 @@ RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule < EvalSlt >
>::apply(node);
@@ -97,7 +97,7 @@ RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool preregister){
// return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<EvalUle>,
RewriteRule<UleMax>,
@@ -109,7 +109,7 @@ RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool preregister){
return RewriteResponse(resultNode == node ? REWRITE_DONE : REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule <EvalSle>,
RewriteRule <SleEliminate>
@@ -117,7 +117,7 @@ RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool preregister){
return RewriteResponse(resultNode == node? REWRITE_DONE : REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<UgtEliminate>
>::apply(node);
@@ -125,7 +125,7 @@ RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<SgtEliminate>
//RewriteRule<SltEliminate>
@@ -134,7 +134,7 @@ RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<UgeEliminate>
>::apply(node);
@@ -142,7 +142,7 @@ RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<SgeEliminate>
// RewriteRule<SleEliminate>
@@ -151,7 +151,7 @@ RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool prerewrite){
Node resultNode = node;
if(RewriteRule<NotXor>::applies(node)) {
@@ -166,7 +166,7 @@ RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool preregister){
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool prerewrite) {
Node resultNode = node;
if (RewriteRule<ExtractConcat>::applies(node)) {
@@ -206,7 +206,7 @@ RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool preregister) {
}
-RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<ConcatFlatten>,
@@ -220,63 +220,70 @@ RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteAnd(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteAnd(TNode node, bool prerewrite) {
Node resultNode = node;
-
resultNode = LinearRewriteStrategy
< RewriteRule<FlattenAssocCommut>,
- RewriteRule<AndSimplify>,
- RewriteRule<BitwiseSlicing>
+ RewriteRule<AndSimplify>
>::apply(node);
- if (resultNode.getKind() != node.getKind()) {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ if (!prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<BitwiseSlicing>
+ >::apply(resultNode);
+
+ if (resultNode.getKind() != node.getKind()) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ }
}
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteOr(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteOr(TNode node, bool prerewrite){
Node resultNode = node;
-
resultNode = LinearRewriteStrategy
< RewriteRule<FlattenAssocCommut>,
- RewriteRule<OrSimplify>,
- RewriteRule<BitwiseSlicing>
- >::apply(node);
+ RewriteRule<OrSimplify>
+ >::apply(node);
- if (resultNode.getKind() != node.getKind()) {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ if (!prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<BitwiseSlicing>
+ >::apply(resultNode);
+
+ if (resultNode.getKind() != node.getKind()) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ }
}
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteXor(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteXor(TNode node, bool prerewrite) {
Node resultNode = node;
-
resultNode = LinearRewriteStrategy
< RewriteRule<FlattenAssocCommut>, // flatten the expression
RewriteRule<XorSimplify>, // simplify duplicates and constants
RewriteRule<XorZero>, // checks if the constant part is zero and eliminates it
RewriteRule<BitwiseSlicing>
- >::apply(node);
-
- // this simplification introduces new terms and might require further
- // rewriting
- if (RewriteRule<XorOne>::applies(resultNode)) {
- resultNode = RewriteRule<XorOne>::run<false> (resultNode);
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
- }
+ >::apply(node);
- if (resultNode.getKind() != node.getKind()) {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ if (!prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<XorOne>,
+ RewriteRule <BitwiseSlicing>
+ >::apply(resultNode);
+
+ if (resultNode.getKind() != node.getKind()) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+ }
}
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<XnorEliminate>
>::apply(node);
@@ -284,7 +291,7 @@ RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<NandEliminate>
>::apply(node);
@@ -292,7 +299,7 @@ RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<NorEliminate>
>::apply(node);
@@ -300,7 +307,7 @@ RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<CompEliminate>
>::apply(node);
@@ -308,7 +315,7 @@ RewriteResponse TheoryBVRewriter::RewriteComp(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool prerewrite) {
Node resultNode = node;
resultNode = LinearRewriteStrategy
@@ -318,7 +325,7 @@ RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool preregister) {
>::apply(node);
// only apply if every subterm was already rewritten
- if (!preregister) {
+ if (!prerewrite) {
// distributes multiplication by constant over +, - and unary -
if(RewriteRule<MultDistribConst>::applies(resultNode)) {
resultNode = RewriteRule<MultDistribConst>::run<false>(resultNode);
@@ -333,23 +340,28 @@ RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewritePlus(TNode node, bool preregister) {
- if (preregister) {
- return RewriteResponse(REWRITE_DONE, node);
+RewriteResponse TheoryBVRewriter::RewritePlus(TNode node, bool prerewrite) {
+ Node resultNode = node;
+ if (prerewrite) {
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<FlattenAssocCommut>
+ >::apply(node);
+ return RewriteResponse(REWRITE_DONE, resultNode);
}
- Node resultNode = LinearRewriteStrategy
- < RewriteRule<FlattenAssocCommut>,
+
+ resultNode = LinearRewriteStrategy
+ < RewriteRule<FlattenAssocCommut>,
RewriteRule<PlusCombineLikeTerms>
- // RewriteRule<PlusLiftConcat>
>::apply(node);
- if (resultNode == node) {
- return RewriteResponse(REWRITE_DONE, resultNode);
- } else {
- return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+
+ if (node != resultNode) {
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
+
+ return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool prerewrite){
// return RewriteResponse(REWRITE_DONE, node);
Node resultNode = LinearRewriteStrategy
< RewriteRule<SubEliminate>
@@ -358,7 +370,7 @@ RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool preregister){
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool prerewrite) {
Node resultNode = node;
resultNode = LinearRewriteStrategy
@@ -372,7 +384,7 @@ RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
- if(!preregister) {
+ if(!prerewrite) {
if (RewriteRule<NegMult>::applies(node)) {
resultNode = RewriteRule<NegMult>::run<false>(node);
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
@@ -382,8 +394,27 @@ RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
+RewriteResponse TheoryBVRewriter::RewriteUdiv(TNode node, bool prerewrite){
+ Node resultNode = node;
+
+ if(node[1].isConst() && node[1].getConst<BitVector>().getValue() != 0) {
+ return RewriteUdivTotal(node, prerewrite);
+ }
-RewriteResponse TheoryBVRewriter::RewriteUdivTotal(TNode node, bool preregister){
+ return RewriteResponse(REWRITE_DONE, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteUrem(TNode node, bool prerewrite){
+ Node resultNode = node;
+
+ if(node[1].isConst() && node[1].getConst<BitVector>().getValue() != 0) {
+ return RewriteUremTotal(node, prerewrite);
+ }
+
+ return RewriteResponse(REWRITE_DONE, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteUdivTotal(TNode node, bool prerewrite){
Node resultNode = node;
if(RewriteRule<UdivPow2>::applies(node)) {
@@ -400,7 +431,7 @@ RewriteResponse TheoryBVRewriter::RewriteUdivTotal(TNode node, bool preregister)
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteUremTotal(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteUremTotal(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<UremPow2>::applies(node)) {
@@ -416,7 +447,7 @@ RewriteResponse TheoryBVRewriter::RewriteUremTotal(TNode node, bool preregister)
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<SmodEliminate>
>::apply(node);
@@ -424,7 +455,7 @@ RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<SdivEliminate>
>::apply(node);
@@ -432,14 +463,14 @@ RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSrem(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSrem(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<SremEliminate>
>::apply(node);
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<ShlByConst>::applies(node)) {
resultNode = RewriteRule<ShlByConst>::run <false> (node);
@@ -454,7 +485,7 @@ RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<LshrByConst>::applies(node)) {
resultNode = RewriteRule<LshrByConst>::run <false> (node);
@@ -469,7 +500,7 @@ RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool preregister) {
return RewriteResponse(REWRITE_DONE, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool prerewrite) {
Node resultNode = node;
if(RewriteRule<AshrByConst>::applies(node)) {
resultNode = RewriteRule<AshrByConst>::run <false> (node);
@@ -485,7 +516,7 @@ RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool preregister) {
}
-RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<RepeatEliminate >
>::apply(node);
@@ -493,7 +524,7 @@ RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool preregister) {
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<ZeroExtendEliminate >
>::apply(node);
@@ -501,7 +532,7 @@ RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool preregister
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<EvalSignExtend>
>::apply(node);
@@ -511,7 +542,7 @@ RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool preregister
}
-RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool preregister) {
+RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<RotateRightEliminate >
>::apply(node);
@@ -519,16 +550,32 @@ RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool preregiste
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteRotateLeft(TNode node, bool preregister){
+RewriteResponse TheoryBVRewriter::RewriteRotateLeft(TNode node, bool prerewrite){
Node resultNode = LinearRewriteStrategy
< RewriteRule<RotateLeftEliminate >
- >::apply(node);
+ >::apply(node);
return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
}
-RewriteResponse TheoryBVRewriter::RewriteEqual(TNode node, bool preregister) {
- if (preregister) {
+RewriteResponse TheoryBVRewriter::RewriteBVToNat(TNode node, bool prerewrite) {
+ Node resultNode = LinearRewriteStrategy
+ < RewriteRule<BVToNatEliminate>
+ >::apply(node);
+
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteIntToBV(TNode node, bool prerewrite) {
+ Node resultNode = LinearRewriteStrategy
+ < RewriteRule<IntToBVEliminate>
+ >::apply(node);
+
+ return RewriteResponse(REWRITE_AGAIN_FULL, resultNode);
+}
+
+RewriteResponse TheoryBVRewriter::RewriteEqual(TNode node, bool prerewrite) {
+ if (prerewrite) {
Node resultNode = LinearRewriteStrategy
< RewriteRule<FailEq>,
RewriteRule<SimplifyEq>,
@@ -593,8 +640,8 @@ void TheoryBVRewriter::initializeRewrites() {
d_rewriteTable [ kind::BITVECTOR_PLUS ] = RewritePlus;
d_rewriteTable [ kind::BITVECTOR_SUB ] = RewriteSub;
d_rewriteTable [ kind::BITVECTOR_NEG ] = RewriteNeg;
- // d_rewriteTable [ kind::BITVECTOR_UDIV ] = RewriteUdiv;
- // d_rewriteTable [ kind::BITVECTOR_UREM ] = RewriteUrem;
+ d_rewriteTable [ kind::BITVECTOR_UDIV ] = RewriteUdiv;
+ d_rewriteTable [ kind::BITVECTOR_UREM ] = RewriteUrem;
d_rewriteTable [ kind::BITVECTOR_UDIV_TOTAL ] = RewriteUdivTotal;
d_rewriteTable [ kind::BITVECTOR_UREM_TOTAL ] = RewriteUremTotal;
d_rewriteTable [ kind::BITVECTOR_SMOD ] = RewriteSmod;
@@ -609,6 +656,9 @@ void TheoryBVRewriter::initializeRewrites() {
d_rewriteTable [ kind::BITVECTOR_SIGN_EXTEND ] = RewriteSignExtend;
d_rewriteTable [ kind::BITVECTOR_ROTATE_RIGHT ] = RewriteRotateRight;
d_rewriteTable [ kind::BITVECTOR_ROTATE_LEFT ] = RewriteRotateLeft;
+
+ d_rewriteTable [ kind::BITVECTOR_TO_NAT ] = RewriteBVToNat;
+ d_rewriteTable [ kind::INT_TO_BITVECTOR ] = RewriteIntToBV;
}
Node TheoryBVRewriter::eliminateBVSDiv(TNode node) {
diff --git a/src/theory/bv/theory_bv_rewriter.h b/src/theory/bv/theory_bv_rewriter.h
index 183b5e8d5..def8e24fe 100644
--- a/src/theory/bv/theory_bv_rewriter.h
+++ b/src/theory/bv/theory_bv_rewriter.h
@@ -78,6 +78,9 @@ class TheoryBVRewriter {
static RewriteResponse RewriteRotateRight(TNode node, bool prerewrite = false);
static RewriteResponse RewriteRotateLeft(TNode node, bool prerewrite = false);
+ static RewriteResponse RewriteBVToNat(TNode node, bool prerewrite = false);
+ static RewriteResponse RewriteIntToBV(TNode node, bool prerewrite = false);
+
public:
static RewriteResponse postRewrite(TNode node);
diff --git a/src/theory/bv/theory_bv_type_rules.h b/src/theory/bv/theory_bv_type_rules.h
index 00284e7ae..67dae0cfa 100644
--- a/src/theory/bv/theory_bv_type_rules.h
+++ b/src/theory/bv/theory_bv_type_rules.h
@@ -29,6 +29,11 @@ class BitVectorConstantTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if (check) {
+ if (n.getConst<BitVector>().getSize() == 0) {
+ throw TypeCheckingExceptionPrivate(n, "constant of size 0");
+ }
+ }
return nodeManager->mkBitVectorType(n.getConst<BitVector>().getSize());
}
};
@@ -190,6 +195,29 @@ public:
}
};
+class BitVectorConversionTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if(n.getKind() == kind::BITVECTOR_TO_NAT) {
+ if(check && !n[0].getType(check).isBitVector()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term");
+ }
+ return nodeManager->integerType();
+ }
+
+ if(n.getKind() == kind::INT_TO_BITVECTOR) {
+ size_t bvSize = n.getOperator().getConst<IntToBitVector>();
+ if(check && !n[0].getType(check).isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting integer term");
+ }
+ return nodeManager->mkBitVectorType(bvSize);
+ }
+
+ InternalError("bv-conversion typerule invoked for non-bv-conversion kind");
+ }
+};
+
class CardinalityComputer {
public:
inline static Cardinality computeCardinality(TypeNode type) {
diff --git a/src/theory/bv/theory_bv_utils.h b/src/theory/bv/theory_bv_utils.h
index 5847bac3e..ab6a615a2 100644
--- a/src/theory/bv/theory_bv_utils.h
+++ b/src/theory/bv/theory_bv_utils.h
@@ -357,7 +357,7 @@ inline Node flattenAnd(std::vector<TNode>& queue) {
}
-// neeed a better name, this is not technically a ground term
+// need a better name, this is not technically a ground term
inline bool isBVGroundTerm(TNode node) {
if (node.getNumChildren() == 0) {
return node.isConst();
diff --git a/src/theory/datatypes/datatypes_rewriter.h b/src/theory/datatypes/datatypes_rewriter.h
index bc6d1f839..186444e0a 100644
--- a/src/theory/datatypes/datatypes_rewriter.h
+++ b/src/theory/datatypes/datatypes_rewriter.h
@@ -21,6 +21,7 @@
#include "theory/rewriter.h"
#include "theory/datatypes/options.h"
+#include "theory/type_enumerator.h"
namespace CVC4 {
namespace theory {
@@ -137,10 +138,16 @@ public:
return RewriteResponse(REWRITE_DONE, in[0][selectorIndex]);
}else{
if( options::dtRewriteErrorSel() ){
- Node gt = in.getType().mkGroundTerm();
+ Node gt;
+ if( in.getType().isSort() ){
+ TypeEnumerator te(in.getType());
+ gt = *te;
+ }else{
+ gt = in.getType().mkGroundTerm();
+ }
TypeNode gtt = gt.getType();
//Assert( gtt.isDatatype() || gtt.isParametricDatatype() );
- if( !gtt.isInstantiatedDatatype() ){
+ if( gtt.isDatatype() && !gtt.isInstantiatedDatatype() ){
gt = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
NodeManager::currentNM()->mkConst(AscriptionType(in.getType().toType())), gt);
}
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index 2e58677df..81ef32b32 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -88,7 +88,7 @@ typerule APPLY_TYPE_ASCRIPTION ::CVC4::theory::datatypes::DatatypeAscriptionType
# constructor applications are constant if they are applied only to constants
construle APPLY_CONSTRUCTOR ::CVC4::theory::datatypes::DatatypeConstructorTypeRule
-operator TUPLE_TYPE 1: "tuple type"
+operator TUPLE_TYPE 0: "tuple type"
cardinality TUPLE_TYPE \
"::CVC4::theory::datatypes::TupleProperties::computeCardinality(%TYPE%)" \
"theory/datatypes/theory_datatypes_type_rules.h"
@@ -100,7 +100,7 @@ enumerator TUPLE_TYPE \
"::CVC4::theory::datatypes::TupleEnumerator" \
"theory/datatypes/type_enumerator.h"
-operator TUPLE 1: "a tuple"
+operator TUPLE 0: "a tuple"
typerule TUPLE ::CVC4::theory::datatypes::TupleTypeRule
construle TUPLE ::CVC4::theory::datatypes::TupleProperties
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 7f96232d6..a0651efb4 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -91,7 +91,7 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( Node n, bool doMake
}
void TheoryDatatypes::check(Effort e) {
-
+ Trace("datatypes-debug") << "Check effort " << e << std::endl;
while(!done() && !d_conflict) {
// Get all the assertions
Assertion assertion = get();
@@ -117,80 +117,95 @@ void TheoryDatatypes::check(Effort e) {
if( e == EFFORT_FULL ) {
Debug("datatypes-split") << "Check for splits " << e << endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
- while( !eqcs_i.isFinished() ){
- Node n = (*eqcs_i);
- if( DatatypesRewriter::isTermDatatype( n ) ){
- EqcInfo* eqc = getOrMakeEqcInfo( n, true );
- //if there are more than 1 possible constructors for eqc
- if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
- const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
- //if only one constructor, then this term must be this constructor
- if( dt.getNumConstructors()==1 ){
- Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
- d_pending.push_back( t );
- d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
- Trace("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
- d_infer.push_back( t );
- }else{
- std::vector< bool > pcons;
- getPossibleCons( eqc, n, pcons );
- //std::cout << "pcons " << n << " = ";
- //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
- //std::cout << std::endl;
- //check if we do not need to resolve the constructor type for this equivalence class.
- // this is if there are no selectors for this equivalence class, its possible values are infinite,
- // and we are not producing a model, then do not split.
- int consIndex = -1;
- bool needSplit = true;
- for( unsigned int j=0; j<pcons.size(); j++ ) {
- if( pcons[j] ) {
- if( consIndex==-1 ){
- consIndex = j;
+ bool addedFact = false;
+ do {
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ if( DatatypesRewriter::isTermDatatype( n ) ){
+ Trace("datatypes-debug") << "Process equivalence class " << n << std::endl;
+ EqcInfo* eqc = getOrMakeEqcInfo( n, true );
+ //if there are more than 1 possible constructors for eqc
+ if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
+ Trace("datatypes-debug") << "No constructor..." << std::endl;
+ const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+ //if only one constructor, then this term must be this constructor
+ if( dt.getNumConstructors()==1 ){
+ Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
+ d_pending.push_back( t );
+ d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
+ Trace("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
+ d_infer.push_back( t );
+ }else{
+ std::vector< bool > pcons;
+ getPossibleCons( eqc, n, pcons );
+ //std::cout << "pcons " << n << " = ";
+ //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
+ //std::cout << std::endl;
+ //check if we do not need to resolve the constructor type for this equivalence class.
+ // this is if there are no selectors for this equivalence class, its possible values are infinite,
+ // and we are not producing a model, then do not split.
+ int consIndex = -1;
+ bool needSplit = true;
+ for( unsigned int j=0; j<pcons.size(); j++ ) {
+ if( pcons[j] ) {
+ if( consIndex==-1 ){
+ consIndex = j;
+ }
+ if( !dt[ j ].isFinite() && !eqc->d_selectors ) {
+ needSplit = false;
+ }
}
- if( !dt[ j ].isFinite() && !eqc->d_selectors ) {
- needSplit = false;
+ }
+ if( !needSplit && mustSpecifyAssignment() ){
+ //for the sake of termination, we must choose the constructor of a ground term
+ //NEED GUARENTEE: groundTerm should not contain any subterms of the same type
+ //** TODO: this is probably not good enough, actually need fair enumeration strategy
+ Node groundTerm = n.getType().mkGroundTerm();
+ int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
+ if( pcons[index] ){
+ consIndex = index;
}
+ needSplit = true;
}
- }
- if( !needSplit && mustSpecifyAssignment() ){
- //for the sake of termination, we must choose the constructor of a ground term
- //NEED GUARENTEE: groundTerm should not contain any subterms of the same type
- //** TODO: this is probably not good enough, actually need fair enumeration strategy
- Node groundTerm = n.getType().mkGroundTerm();
- int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
- if( pcons[index] ){
- consIndex = index;
+ if( needSplit && consIndex!=-1 ) {
+ Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
+ Trace("dt-split") << "*************Split for possible constructor " << dt[consIndex] << " for " << n << endl;
+ test = Rewriter::rewrite( test );
+ NodeBuilder<> nb(kind::OR);
+ nb << test << test.notNode();
+ Node lemma = nb;
+ d_out->lemma( lemma );
+ d_out->requirePhase( test, true );
+ return;
+ }else{
+ Trace("dt-split") << "Do not split constructor for " << n << std::endl;
}
- needSplit = true;
- }
- if( needSplit && consIndex!=-1 ) {
- Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
- Trace("dt-split") << "*************Split for possible constructor " << dt[consIndex] << " for " << n << endl;
- test = Rewriter::rewrite( test );
- NodeBuilder<> nb(kind::OR);
- nb << test << test.notNode();
- Node lemma = nb;
- d_out->lemma( lemma );
- d_out->requirePhase( test, true );
- return;
- }else{
- Trace("dt-split") << "Do not split constructor for " << n << std::endl;
}
+ }else{
+ Trace("datatypes-debug") << "Has constructor " << eqc->d_constructor.get() << std::endl;
}
}
+ ++eqcs_i;
}
- ++eqcs_i;
- }
- flushPendingFacts();
- if( !d_conflict ){
- if( options::dtRewriteErrorSel() ){
- collapseSelectors();
- flushPendingFacts();
+ Trace("datatypes-debug") << "Flush pending facts..." << std::endl;
+ addedFact = !d_pending.empty() || !d_pending_merge.empty();
+ flushPendingFacts();
+ if( !d_conflict ){
+ if( options::dtRewriteErrorSel() ){
+ bool innerAddedFact = false;
+ do {
+ collapseSelectors();
+ innerAddedFact = !d_pending.empty() || !d_pending_merge.empty();
+ flushPendingFacts();
+ }while( !d_conflict && innerAddedFact );
+ }
}
- }
+ }while( !d_conflict && addedFact );
+ Trace("datatypes-debug") << "Finished. " << d_conflict << std::endl;
if( !d_conflict ){
- // printModelDebug();
+ Trace("dt-model-test") << std::endl;
+ printModelDebug("dt-model-test");
}
}
@@ -1003,8 +1018,8 @@ bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
// (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) )
//We may need to communicate (3) outwards if the conclusions involve other theories
Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl;
+ bool addLemma = false;
if( ( n.getKind()==EQUAL || n.getKind()==IFF) && n[1].getKind()==APPLY_CONSTRUCTOR && exp.getKind()!=EQUAL ){
- bool addLemma = false;
#if 1
const Datatype& dt = ((DatatypeType)(n[1].getType()).toType()).getDatatype();
addLemma = dt.involvesExternalType();
@@ -1028,6 +1043,11 @@ bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
}
}
}
+ //else if( exp.getKind()==APPLY_TESTER ){
+ //if( n.getKind()==EQUAL && !DatatypesRewriter::isTermDatatype( n[0] ) ){
+ // return true;
+ //}
+ //}
Trace("dt-lemma-debug") << "Do not need to communicate " << n << std::endl;
return false;
}
@@ -1066,6 +1086,10 @@ Node TheoryDatatypes::getRepresentative( Node a ){
void TheoryDatatypes::printModelDebug( const char* c ){
+ if(! (Trace.isOn(c))) {
+ return;
+ }
+
Trace( c ) << "Datatypes model : " << std::endl;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
diff --git a/src/theory/idl/Makefile b/src/theory/idl/Makefile
new file mode 100644
index 000000000..75ae33c7e
--- /dev/null
+++ b/src/theory/idl/Makefile
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/theory/idl
+
+include $(topdir)/Makefile.subdir
diff --git a/src/theory/idl/Makefile.am b/src/theory/idl/Makefile.am
new file mode 100644
index 000000000..4297e3bdb
--- /dev/null
+++ b/src/theory/idl/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -D__BUILDING_CVC4LIB \
+ -I@builddir@/../.. -I@srcdir@/../../include -I@srcdir@/../..
+AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
+
+noinst_LTLIBRARIES = libidl.la
+
+libidl_la_SOURCES = \
+ idl_model.h \
+ idl_model.cpp \
+ idl_assertion.h \
+ idl_assertion.cpp \
+ idl_assertion_db.h \
+ idl_assertion_db.cpp \
+ theory_idl.h \
+ theory_idl.cpp
+
+EXTRA_DIST = \
+ kinds
diff --git a/src/theory/idl/idl_assertion.cpp b/src/theory/idl/idl_assertion.cpp
new file mode 100644
index 000000000..1e725932b
--- /dev/null
+++ b/src/theory/idl/idl_assertion.cpp
@@ -0,0 +1,213 @@
+/********************* */
+/*! \file idl_assertion.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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
new file mode 100644
index 000000000..8ce0e93b2
--- /dev/null
+++ b/src/theory/idl/idl_assertion.h
@@ -0,0 +1,91 @@
+/********************* */
+/*! \file idl_assertion.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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
new file mode 100644
index 000000000..697c70c02
--- /dev/null
+++ b/src/theory/idl/idl_assertion_db.cpp
@@ -0,0 +1,59 @@
+/********************* */
+/*! \file idl_assertion_db.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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
new file mode 100644
index 000000000..0501bc6bf
--- /dev/null
+++ b/src/theory/idl/idl_assertion_db.h
@@ -0,0 +1,86 @@
+/********************* */
+/*! \file idl_assertion_db.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 inndex 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
new file mode 100644
index 000000000..75f4834ea
--- /dev/null
+++ b/src/theory/idl/idl_model.cpp
@@ -0,0 +1,64 @@
+/********************* */
+/*! \file idl_model.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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.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.constraint << std::endl;
+ reasons.push_back(reason.constraint);
+ current = reason.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
new file mode 100644
index 000000000..64407684b
--- /dev/null
+++ b/src/theory/idl/idl_model.h
@@ -0,0 +1,84 @@
+/********************* */
+/*! \file idl_model.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "expr/node.h"
+#include "context/cdhashmap.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 x;
+ /** The constraint of the reaason */
+ TNode constraint;
+
+ IDLReason(TNode x, TNode constraint)
+ : x(x), 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;
+}
+
+}
+}
+}
diff --git a/src/theory/idl/kinds b/src/theory/idl/kinds
new file mode 100644
index 000000000..6bf0218b0
--- /dev/null
+++ b/src/theory/idl/kinds
@@ -0,0 +1,8 @@
+# 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/options b/src/theory/idl/options
new file mode 100644
index 000000000..c1c9edcef
--- /dev/null
+++ b/src/theory/idl/options
@@ -0,0 +1,12 @@
+#
+# Option specification file for CVC4
+# See src/options/base_options for a description of this file format
+#
+
+module IDL "theory/idl/options.h" Idl
+
+option idlRewriteEq --enable-idl-rewrite-equalities/--disable-idl-rewrite-equalities bool :default false :read-write
+ enable rewriting equalities into two inequalities in IDL solver (default is disabled)
+/disable rewriting equalities into two inequalities in IDL solver (default is disabled)
+
+endmodule
diff --git a/src/theory/idl/theory_idl.cpp b/src/theory/idl/theory_idl.cpp
new file mode 100644
index 000000000..e5100fc71
--- /dev/null
+++ b/src/theory/idl/theory_idl.cpp
@@ -0,0 +1,143 @@
+/********************* */
+/*! \file theory_idl.cpp
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "theory/idl/options.h"
+#include "theory/rewriter.h"
+
+#include <set>
+#include <queue>
+
+using namespace std;
+
+using namespace CVC4;
+using namespace theory;
+using namespace idl;
+
+TheoryIdl::TheoryIdl(context::Context* c, context::UserContext* u, OutputChannel& out,
+ Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe)
+: Theory(THEORY_ARITH, c, u, out, valuation, logicInfo, qe)
+, 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) {
+
+ while(!done()) {
+
+ // Get the next assertion
+ Assertion assertion = get();
+ Debug("theory::idl") << "TheoryIdl::check(): processing " << assertion.assertion << std::endl;
+
+ // Convert the assertion into the internal representation
+ IDLAssertion idlAssertion(assertion.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;
+}
diff --git a/src/theory/idl/theory_idl.h b/src/theory/idl/theory_idl.h
new file mode 100644
index 000000000..c629ad2b0
--- /dev/null
+++ b/src/theory/idl/theory_idl.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file theory_idl.h
+ ** \verbatim
+ ** Original author: Dejan Jovanovic
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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, QuantifiersEngine* qe);
+
+ /** Pre-processing of input atoms */
+ Node ppRewrite(TNode atom);
+
+ /** Check the assertions for satisfiability */
+ void check(Effort effort);
+
+ /** Identity string */
+ std::string identify() const { return "THEORY_IDL"; }
+
+};/* class TheoryIdl */
+
+}/* CVC4::theory::idl namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/ite_simplifier.cpp b/src/theory/ite_simplifier.cpp
index ec9eb27d4..463a9c41a 100644
--- a/src/theory/ite_simplifier.cpp
+++ b/src/theory/ite_simplifier.cpp
@@ -33,7 +33,7 @@ bool ITESimplifier::containsTermITE(TNode e)
}
hash_map<Node, bool, NodeHashFunction>::iterator it;
- it = d_containsTermITECache.find(e);
+ it = d_containsTermITECache.find(e);
if (it != d_containsTermITECache.end()) {
return (*it).second;
}
@@ -60,7 +60,7 @@ bool ITESimplifier::leavesAreConst(TNode e, TheoryId tid)
}
hash_map<Node, bool, NodeHashFunction>::iterator it;
- it = d_leavesConstCache.find(e);
+ it = d_leavesConstCache.find(e);
if (it != d_leavesConstCache.end()) {
return (*it).second;
}
diff --git a/src/theory/ite_simplifier.h b/src/theory/ite_simplifier.h
index 0f648f91d..07fa0dedb 100644
--- a/src/theory/ite_simplifier.h
+++ b/src/theory/ite_simplifier.h
@@ -31,9 +31,7 @@
#include "prop/prop_engine.h"
#include "context/cdhashset.h"
#include "theory/theory.h"
-#include "theory/substitutions.h"
#include "theory/rewriter.h"
-#include "theory/substitutions.h"
#include "theory/shared_terms_database.h"
#include "theory/term_registration_visitor.h"
#include "theory/valuation.h"
@@ -43,6 +41,7 @@
#include "util/ite_removal.h"
namespace CVC4 {
+namespace theory {
class ITESimplifier {
Node d_true;
@@ -160,6 +159,7 @@ public:
};
-}
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
#endif
diff --git a/src/theory/logic_info.cpp b/src/theory/logic_info.cpp
index dc9de8662..d74f36069 100644
--- a/src/theory/logic_info.cpp
+++ b/src/theory/logic_info.cpp
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Morgan Deters
** Major contributors: none
- ** Minor contributors (to current version): Dejan Jovanovic
+ ** Minor contributors (to current version): Dejan Jovanovic, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -105,6 +105,10 @@ std::string LogicInfo::getLogicString() const {
ss << "DT";
++seen;
}
+ if(d_theories[THEORY_STRINGS]) {
+ ss << "S";
+ ++seen;
+ }
if(d_theories[THEORY_ARITH]) {
if(isDifferenceLogic()) {
ss << (areIntegersUsed() ? "I" : "");
@@ -177,10 +181,21 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
enableTheory(THEORY_ARRAY);
++p;
}
+ if(*p == 'S') {
+ // Strings requires arith for length constraints,
+ // and UF for equality (?)
+ enableTheory(THEORY_STRINGS);
+ enableTheory(THEORY_UF);
+ enableTheory(THEORY_ARITH);
+ enableIntegers();
+ arithOnlyLinear();
+ ++p;
+ }
if(!strncmp(p, "UF", 2)) {
enableTheory(THEORY_UF);
p += 2;
}
+ // allow BV or DT in either order
if(!strncmp(p, "BV", 2)) {
enableTheory(THEORY_BV);
p += 2;
@@ -189,6 +204,10 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
enableTheory(THEORY_DATATYPES);
p += 2;
}
+ if(!d_theories[THEORY_BV] && !strncmp(p, "BV", 2)) {
+ enableTheory(THEORY_BV);
+ p += 2;
+ }
if(!strncmp(p, "IDL", 3)) {
enableIntegers();
disableReals();
@@ -241,7 +260,12 @@ void LogicInfo::setLogicString(std::string logicString) throw(IllegalArgumentExc
}
if(*p != '\0') {
stringstream err;
- err << "LogicInfo::setLogicString(): junk (\"" << p << "\") at end of logic string: " << logicString;
+ err << "LogicInfo::setLogicString(): ";
+ if(p == logicString) {
+ err << "cannot parse logic string: " << logicString;
+ } else {
+ err << "junk (\"" << p << "\") at end of logic string: " << logicString;
+ }
IllegalArgument(logicString, err.str().c_str());
}
diff --git a/src/theory/logic_info.h b/src/theory/logic_info.h
index c7b5c58f9..2448898c0 100644
--- a/src/theory/logic_info.h
+++ b/src/theory/logic_info.h
@@ -155,21 +155,25 @@ public:
/** Are integers in this logic? */
bool areIntegersUsed() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether integers are used");
return d_integers;
}
/** Are reals in this logic? */
bool areRealsUsed() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether reals are used");
return d_reals;
}
/** Does this logic only linear arithmetic? */
bool isLinear() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether it's linear");
return d_linear || d_differenceLogic;
}
/** Does this logic only permit difference reasoning? (implies linear) */
bool isDifferenceLogic() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
+ CheckArgument(isTheoryEnabled(theory::THEORY_ARITH), *this, "Arithmetic not used in this LogicInfo; cannot ask whether it's difference logic");
return d_differenceLogic;
}
diff --git a/src/theory/model.cpp b/src/theory/model.cpp
index 1c511be30..840c8bc3a 100644
--- a/src/theory/model.cpp
+++ b/src/theory/model.cpp
@@ -19,6 +19,7 @@
#include "smt/options.h"
#include "smt/smt_engine.h"
#include "theory/uf/theory_uf_model.h"
+#include "theory/uf/options.h"
using namespace std;
using namespace CVC4;
@@ -27,7 +28,7 @@ using namespace CVC4::context;
using namespace CVC4::theory;
TheoryModel::TheoryModel( context::Context* c, std::string name, bool enableFuncModels) :
- d_substitutions(c), d_equalityEngine(c, name), d_modelBuilt(c, false), d_enableFuncModels(enableFuncModels)
+ d_substitutions(c, false), d_equalityEngine(c, name), d_modelBuilt(c, false), d_enableFuncModels(enableFuncModels)
{
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
@@ -47,12 +48,15 @@ void TheoryModel::reset(){
d_uf_models.clear();
}
-Node TheoryModel::getValue( TNode n ) const{
+Node TheoryModel::getValue(TNode n) const {
//apply substitutions
- Node nn = d_substitutions.apply( n );
+ Node nn = d_substitutions.apply(n);
//get value in model
- nn = getModelValue( nn );
- Assert(nn.isConst() || nn.getKind() == kind::LAMBDA);
+ nn = getModelValue(nn);
+ if(options::condenseFunctionValues() || nn.getKind() != kind::LAMBDA) {
+ //normalize
+ nn = Rewriter::rewrite(nn);
+ }
return nn;
}
@@ -94,16 +98,15 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
// no good. Instead, return the quantifier itself. If we're in
// checkModel(), and the quantifier actually matters, we'll get an
// assert-fail since the quantifier isn't a constant.
- if(!d_equalityEngine.hasTerm(n)) {
+ if(!d_equalityEngine.hasTerm(Rewriter::rewrite(n))) {
return n;
+ } else {
+ n = Rewriter::rewrite(n);
}
} else {
if(n.getKind() == kind::LAMBDA) {
NodeManager* nm = NodeManager::currentNM();
Node body = getModelValue(n[1], true);
- // This is a bit ugly, but cache inside simplifier can change, so can't be const
- // The ite simplifier is needed to get rid of artifacts created by Boolean terms
- body = const_cast<ITESimplifier*>(&d_iteSimp)->simpITE(body);
body = Rewriter::rewrite(body);
return nm->mkNode(kind::LAMBDA, n[0], body);
}
@@ -430,6 +433,7 @@ void TheoryEngineModelBuilder::checkTerms(TNode n, TheoryModel* tm, NodeSet& cac
void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
{
+ Trace("model-builder") << "TheoryEngineModelBuilder: buildModel, fullModel = " << fullModel << std::endl;
TheoryModel* tm = (TheoryModel*)m;
// buildModel with fullModel = true should only be called once in any context
@@ -718,6 +722,7 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
}
if (!fullModel) {
+ Trace("model-builder") << "Make sure ECs have reps..." << std::endl;
// Make sure every EC has a rep
for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap ) {
tm->d_reps[itMap->first] = itMap->second;
@@ -851,8 +856,10 @@ void TheoryEngineModelBuilder::processBuildModel(TheoryModel* m, bool fullModel)
default_v = (*te);
}
ufmt.setDefaultValue( m, default_v );
- ufmt.simplify();
- Node val = ufmt.getFunctionValue( "_ufmt_" );
+ if(options::condenseFunctionValues()) {
+ ufmt.simplify();
+ }
+ Node val = ufmt.getFunctionValue( "_ufmt_", options::condenseFunctionValues() );
Trace("model-builder") << " Assigning (" << n << ") to (" << val << ")" << endl;
m->d_uf_models[n] = val;
//ufmt.debugPrint( std::cout, m );
diff --git a/src/theory/options b/src/theory/options
index 5d752fca1..9944264c8 100644
--- a/src/theory/options
+++ b/src/theory/options
@@ -5,8 +5,8 @@
module THEORY "theory/options.h" Theory layer
-expert-option theoryOfMode --theoryof-mode=MODE CVC4::theory::TheoryOfMode :handler CVC4::theory::stringToTheoryOfMode :handler-include "theory/options_handlers.h" :default CVC4::theory::THEORY_OF_TYPE_BASED :include "theory/theoryof_mode.h"
- mode for theoryof
+expert-option theoryOfMode theoryof-mode --theoryof-mode=MODE CVC4::theory::TheoryOfMode :handler CVC4::theory::stringToTheoryOfMode :handler-include "theory/options_handlers.h" :default CVC4::theory::THEORY_OF_TYPE_BASED :include "theory/theoryof_mode.h" :read-write
+ mode for Theory::theoryof()
option - use-theory --use-theory=NAME argument :handler CVC4::theory::useTheory :handler-include "theory/options_handlers.h"
use alternate theory implementation NAME (--use-theory=help for a list)
diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h
index af3065404..44b89e8cb 100644
--- a/src/theory/output_channel.h
+++ b/src/theory/output_channel.h
@@ -127,9 +127,12 @@ public:
*/
LemmaStatus split(TNode n)
throw(TypeCheckingExceptionPrivate, AssertionException) {
- return lemma(n.orNode(n.notNode()));
+ return splitLemma(n.orNode(n.notNode()));
}
+ virtual LemmaStatus splitLemma(TNode n, bool removable = false)
+ throw(TypeCheckingExceptionPrivate, AssertionException) = 0;
+
/**
* If a decision is made on n, it must be in the phase specified.
* Note that this is enforced *globally*, i.e., it is completely
@@ -219,7 +222,7 @@ public:
/** Demands that the search restart from sat search level 0.
* Using this leads to non-termination issues.
- * It is appropraite for prototyping for theories.
+ * It is appropriate for prototyping for theories.
*/
virtual void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException) {}
diff --git a/src/theory/quantifiers/Makefile.am b/src/theory/quantifiers/Makefile.am
index 7fea8cf3a..be24d6c67 100644
--- a/src/theory/quantifiers/Makefile.am
+++ b/src/theory/quantifiers/Makefile.am
@@ -23,8 +23,6 @@ libquantifiers_la_SOURCES = \
model_engine.cpp \
modes.cpp \
modes.h \
- relevant_domain.h \
- relevant_domain.cpp \
term_database.h \
term_database.cpp \
first_order_model.h \
@@ -44,7 +42,20 @@ libquantifiers_la_SOURCES = \
inst_strategy_e_matching.h \
inst_strategy_e_matching.cpp \
inst_strategy_cbqi.h \
- inst_strategy_cbqi.cpp
+ inst_strategy_cbqi.cpp \
+ full_model_check.h \
+ full_model_check.cpp \
+ bounded_integers.h \
+ bounded_integers.cpp \
+ first_order_reasoning.h \
+ first_order_reasoning.cpp \
+ rewrite_engine.h \
+ rewrite_engine.cpp \
+ relevant_domain.h \
+ relevant_domain.cpp \
+ symmetry_breaking.h \
+ symmetry_breaking.cpp
+
EXTRA_DIST = \
kinds \
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
new file mode 100644
index 000000000..30ff5242b
--- /dev/null
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -0,0 +1,372 @@
+/********************* */
+/*! \file bounded_integers.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Bounded integers module
+ **
+ ** This class manages integer bounds for quantifiers
+ **/
+
+#include "theory/quantifiers/bounded_integers.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/model_engine.h"
+
+using namespace CVC4;
+using namespace std;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+
+void BoundedIntegers::RangeModel::initialize() {
+ //add initial split lemma
+ Node ltr = NodeManager::currentNM()->mkNode( LT, d_range, NodeManager::currentNM()->mkConst( Rational(0) ) );
+ ltr = Rewriter::rewrite( ltr );
+ Trace("bound-int-lemma") << " *** bound int: initial split on " << ltr << std::endl;
+ d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
+ Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
+ d_range_literal[-1] = ltr_lit;
+ d_lit_to_range[ltr_lit] = -1;
+ d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
+ //register with bounded integers
+ Trace("bound-int-debug") << "Literal " << ltr_lit << " is literal for " << d_range << std::endl;
+ d_bi->addLiteralFromRange(ltr_lit, d_range);
+}
+
+void BoundedIntegers::RangeModel::assertNode(Node n) {
+ bool pol = n.getKind()!=NOT;
+ Node nlit = n.getKind()==NOT ? n[0] : n;
+ if( d_lit_to_range.find( nlit )!=d_lit_to_range.end() ){
+ Trace("bound-int-assert") << "With polarity = " << pol << " (req "<< d_lit_to_pol[nlit] << ")";
+ Trace("bound-int-assert") << ", found literal " << nlit;
+ Trace("bound-int-assert") << ", it is bound literal " << d_lit_to_range[nlit] << " for " << d_range << std::endl;
+ d_range_assertions[nlit] = (pol==d_lit_to_pol[nlit]);
+ if( pol!=d_lit_to_pol[nlit] ){
+ //check if we need a new split?
+ if( !d_has_range ){
+ bool needsRange = true;
+ for( std::map< Node, int >::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
+ if( d_range_assertions.find( it->first )==d_range_assertions.end() ){
+ needsRange = false;
+ break;
+ }
+ }
+ if( needsRange ){
+ allocateRange();
+ }
+ }
+ }else{
+ if (!d_has_range || d_lit_to_range[nlit]<d_curr_range ){
+ Trace("bound-int-bound") << "Successfully bound " << d_range << " to " << d_lit_to_range[nlit] << std::endl;
+ d_curr_range = d_lit_to_range[nlit];
+ }
+ //set the range
+ d_has_range = true;
+ }
+ }else{
+ Message() << "Could not find literal " << nlit << " for range " << d_range << std::endl;
+ exit(0);
+ }
+}
+
+void BoundedIntegers::RangeModel::allocateRange() {
+ d_curr_max++;
+ int newBound = d_curr_max;
+ Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl;
+ //TODO: newBound should be chosen in a smarter way
+ Node ltr = NodeManager::currentNM()->mkNode( LEQ, d_range, NodeManager::currentNM()->mkConst( Rational(newBound) ) );
+ ltr = Rewriter::rewrite( ltr );
+ Trace("bound-int-lemma") << " *** bound int: split on " << ltr << std::endl;
+ d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
+ Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
+ d_range_literal[newBound] = ltr_lit;
+ d_lit_to_range[ltr_lit] = newBound;
+ d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
+ //register with bounded integers
+ d_bi->addLiteralFromRange(ltr_lit, d_range);
+}
+
+Node BoundedIntegers::RangeModel::getNextDecisionRequest() {
+ //request the current cardinality as a decision literal, if not already asserted
+ for( std::map< Node, int >::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
+ int i = it->second;
+ if( !d_has_range || i<d_curr_range ){
+ Node rn = it->first;
+ Assert( !rn.isNull() );
+ if( d_range_assertions.find( rn )==d_range_assertions.end() ){
+ if (!d_lit_to_pol[it->first]) {
+ rn = rn.negate();
+ }
+ Trace("bound-int-dec") << "For " << d_range << ", make decision " << rn << " to make range " << i << std::endl;
+ return rn;
+ }
+ }
+ }
+ return Node::null();
+}
+
+
+BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) :
+QuantifiersModule(qe), d_assertions(c){
+
+}
+
+bool BoundedIntegers::isBound( Node f, Node v ) {
+ return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end();
+}
+
+bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
+ if( b.getKind()==BOUND_VARIABLE ){
+ if( !isBound( f, b ) ){
+ return true;
+ }
+ }else{
+ for( unsigned i=0; i<b.getNumChildren(); i++ ){
+ if( hasNonBoundVar( f, b[i] ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void BoundedIntegers::processLiteral( Node f, Node lit, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map ) {
+ if( lit.getKind()==GEQ && lit[0].getType().isInteger() ){
+ std::map< Node, Node > msum;
+ if (QuantArith::getMonomialSumLit( lit, msum )){
+ Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl;
+ for(std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ Trace("bound-int-debug") << " ";
+ if( !it->second.isNull() ){
+ Trace("bound-int-debug") << it->second;
+ if( !it->first.isNull() ){
+ Trace("bound-int-debug") << " * ";
+ }
+ }
+ if( !it->first.isNull() ){
+ Trace("bound-int-debug") << it->first;
+ }
+ Trace("bound-int-debug") << std::endl;
+ }
+ Trace("bound-int-debug") << std::endl;
+ for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( f, it->first ) ){
+ Node veq;
+ if( QuantArith::isolate( it->first, msum, veq, GEQ ) ){
+ Node n1 = veq[0];
+ Node n2 = veq[1];
+ if(pol){
+ //flip
+ n1 = veq[1];
+ n2 = veq[0];
+ if( n1.getKind()==BOUND_VARIABLE ){
+ n2 = QuantArith::offset( n2, 1 );
+ }else{
+ n1 = QuantArith::offset( n1, -1 );
+ }
+ veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
+ }
+ Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
+ Node bv = n1.getKind()==BOUND_VARIABLE ? n1 : n2;
+ if( !isBound( f, bv ) ){
+ if( !hasNonBoundVar( f, n1.getKind()==BOUND_VARIABLE ? n2 : n1 ) ) {
+ Trace("bound-int-debug") << "The bound is relevant." << std::endl;
+ int loru = n1.getKind()==BOUND_VARIABLE ? 0 : 1;
+ d_bounds[loru][f][bv] = (n1.getKind()==BOUND_VARIABLE ? n2 : n1);
+ bound_lit_map[loru][bv] = lit;
+ bound_lit_pol_map[loru][bv] = pol;
+ }
+ }
+ }
+ }
+ }
+ }
+ }else if( lit.getKind()==LEQ || lit.getKind()==LT || lit.getKind()==GT ) {
+ Message() << "BoundedIntegers : Bad kind for literal : " << lit << std::endl;
+ exit(0);
+ }
+}
+
+void BoundedIntegers::process( Node f, Node n, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map ){
+ if( (( n.getKind()==IMPLIES || n.getKind()==OR) && pol) || (n.getKind()==AND && !pol) ){
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ bool newPol = n.getKind()==IMPLIES && i==0 ? !pol : pol;
+ process( f, n[i], newPol, bound_lit_map, bound_lit_pol_map );
+ }
+ }else if( n.getKind()==NOT ){
+ process( f, n[0], !pol, bound_lit_map, bound_lit_pol_map );
+ }else {
+ processLiteral( f, n, pol, bound_lit_map, bound_lit_pol_map );
+ }
+}
+
+void BoundedIntegers::check( Theory::Effort e ) {
+
+}
+
+
+void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) {
+ d_lit_to_ranges[lit].push_back(r);
+ //check if it is already asserted?
+ if(d_assertions.find(lit)!=d_assertions.end()){
+ d_rms[r]->assertNode( d_assertions[lit] ? lit : lit.negate() );
+ }
+}
+
+void BoundedIntegers::registerQuantifier( Node f ) {
+ Trace("bound-int") << "Register quantifier " << f << std::endl;
+ bool hasIntType = false;
+ int finiteTypes = 0;
+ std::map< Node, int > numMap;
+ for( unsigned i=0; i<f[0].getNumChildren(); i++) {
+ numMap[f[0][i]] = i;
+ if( f[0][i].getType().isInteger() ){
+ hasIntType = true;
+ }
+ else if( f[0][i].getType().isSort() ){
+ finiteTypes++;
+ }
+ }
+ if( hasIntType ){
+ bool success;
+ do{
+ std::map< int, std::map< Node, Node > > bound_lit_map;
+ std::map< int, std::map< Node, bool > > bound_lit_pol_map;
+ success = false;
+ process( f, f[1], true, bound_lit_map, bound_lit_pol_map );
+ for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
+ Node v = it->first;
+ if( !isBound(f,v) ){
+ if( d_bounds[1][f].find(v)!=d_bounds[1][f].end() ){
+ d_set[f].push_back(v);
+ d_set_nums[f].push_back(numMap[v]);
+ success = true;
+ //set Attributes on literals
+ for( unsigned b=0; b<2; b++ ){
+ Assert( bound_lit_map[b].find( v )!=bound_lit_map[b].end() );
+ Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() );
+ BoundIntLitAttribute bila;
+ bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 );
+ }
+ Trace("bound-int") << "Variable " << v << " is bound because of literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
+ }
+ }
+ }
+ }while( success );
+ Trace("bound-int") << "Bounds are : " << std::endl;
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ Node v = d_set[f][i];
+ Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
+ d_range[f][v] = Rewriter::rewrite( r );
+ Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
+ }
+ if( d_set[f].size()==(f[0].getNumChildren()-finiteTypes) ){
+ d_bound_quants.push_back( f );
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ Node v = d_set[f][i];
+ Node r = d_range[f][v];
+ if( quantifiers::TermDb::hasBoundVarAttr(r) ){
+ //introduce a new bound
+ Node new_range = NodeManager::currentNM()->mkSkolem( "bir_$$", r.getType(), "bound for term" );
+ d_nground_range[f][v] = d_range[f][v];
+ d_range[f][v] = new_range;
+ r = new_range;
+ }
+ if( r.getKind()!=CONST_RATIONAL ){
+ if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){
+ Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << " " << r.getKind() << std::endl;
+ d_ranges.push_back( r );
+ d_rms[r] = new RangeModel(this, r, d_quantEngine->getSatContext() );
+ d_rms[r]->initialize();
+ }
+ }
+ }
+ }else{
+ Trace("bound-int-warn") << "Warning : Bounded Integers : Could not find bounds for " << f << std::endl;
+ }
+ }
+}
+
+void BoundedIntegers::assertNode( Node n ) {
+ Trace("bound-int-assert") << "Assert " << n << std::endl;
+ Node nlit = n.getKind()==NOT ? n[0] : n;
+ if( d_lit_to_ranges.find(nlit)!=d_lit_to_ranges.end() ){
+ Trace("bound-int-assert") << "This is the bounding literal for " << d_lit_to_ranges[nlit].size() << " ranges." << std::endl;
+ for( unsigned i=0; i<d_lit_to_ranges[nlit].size(); i++) {
+ Node r = d_lit_to_ranges[nlit][i];
+ Trace("bound-int-assert") << " ...this is a bounding literal for " << r << std::endl;
+ d_rms[r]->assertNode( n );
+ }
+ }
+ d_assertions[nlit] = n.getKind()!=NOT;
+}
+
+Node BoundedIntegers::getNextDecisionRequest() {
+ Trace("bound-int-dec") << "bi: Get next decision request?" << std::endl;
+ for( unsigned i=0; i<d_ranges.size(); i++) {
+ Node d = d_rms[d_ranges[i]]->getNextDecisionRequest();
+ if (!d.isNull()) {
+ return d;
+ }
+ }
+ return Node::null();
+}
+
+void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
+ l = d_bounds[0][f][v];
+ u = d_bounds[1][f][v];
+ if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){
+ //must create substitution
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
+ for( unsigned i=0; i<d_set[f].size(); i++) {
+ if( d_set[f][i]!=v ){
+ Trace("bound-int-rsi") << "Look up the value for " << d_set[f][i] << " " << rsi->d_var_order[d_set_nums[f][i]] << std::endl;
+ Trace("bound-int-rsi") << "term : " << rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]) << std::endl;
+ vars.push_back(d_set[f][i]);
+ subs.push_back(rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]));
+ }else{
+ break;
+ }
+ }
+ Trace("bound-int-rsi") << "Do substitution..." << std::endl;
+ //check if it has been instantiated
+ if (!vars.empty() && !d_bnd_it[f][v].hasInstantiated(subs)){
+ //must add the lemma
+ Node nn = d_nground_range[f][v];
+ nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[f][v] );
+ Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
+ d_quantEngine->getOutputChannel().lemma(lem);
+ l = Node::null();
+ u = Node::null();
+ return;
+ }else{
+ u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }
+ }
+}
+
+void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
+ getBounds( f, v, rsi, l, u );
+ Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
+ l = d_quantEngine->getModel()->getCurrentModelValue( l );
+ u = d_quantEngine->getModel()->getCurrentModelValue( u );
+ Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
+ return;
+}
+
+bool BoundedIntegers::isGroundRange(Node f, Node v) {
+ return isBoundVar(f,v) && !quantifiers::TermDb::hasBoundVarAttr(getLowerBound(f,v)) && !quantifiers::TermDb::hasBoundVarAttr(getUpperBound(f,v));
+}
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
new file mode 100644
index 000000000..3da938d31
--- /dev/null
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -0,0 +1,127 @@
+/********************* */
+/*! \file bounded_integers.h
+** \verbatim
+** Original author: Andrew Reynolds
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2013 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief This class manages integer bounds for quantifiers
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BOUNDED_INTEGERS_H
+#define __CVC4__BOUNDED_INTEGERS_H
+
+
+#include "theory/quantifiers_engine.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+
+class RepSetIterator;
+
+namespace quantifiers {
+
+
+class BoundedIntegers : public QuantifiersModule
+{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+private:
+ //for determining bounds
+ bool isBound( Node f, Node v );
+ bool hasNonBoundVar( Node f, Node b );
+ std::map< Node, std::map< Node, Node > > d_bounds[2];
+ std::map< Node, std::vector< Node > > d_set;
+ std::map< Node, std::vector< int > > d_set_nums;
+ std::map< Node, std::map< Node, Node > > d_range;
+ std::map< Node, std::map< Node, Node > > d_nground_range;
+ void hasFreeVar( Node f, Node n );
+ void process( Node f, Node n, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ void processLiteral( Node f, Node lit, bool pol,
+ std::map< int, std::map< Node, Node > >& bound_lit_map,
+ std::map< int, std::map< Node, bool > >& bound_lit_pol_map );
+ std::vector< Node > d_bound_quants;
+private:
+ class RangeModel {
+ private:
+ BoundedIntegers * d_bi;
+ void allocateRange();
+ public:
+ RangeModel(BoundedIntegers * bi, Node r, context::Context* c) : d_bi(bi),
+ d_range(r), d_curr_max(-1), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1) {}
+ Node d_range;
+ int d_curr_max;
+ std::map< int, Node > d_range_literal;
+ std::map< Node, bool > d_lit_to_pol;
+ std::map< Node, int > d_lit_to_range;
+ NodeBoolMap d_range_assertions;
+ context::CDO< bool > d_has_range;
+ context::CDO< int > d_curr_range;
+ void initialize();
+ void assertNode(Node n);
+ Node getNextDecisionRequest();
+ };
+private:
+ //information for minimizing ranges
+ std::vector< Node > d_ranges;
+ //map to range model objects
+ std::map< Node, RangeModel * > d_rms;
+ //literal to range
+ std::map< Node, std::vector< Node > > d_lit_to_ranges;
+ //list of currently asserted arithmetic literals
+ NodeBoolMap d_assertions;
+private:
+ //class to store whether bounding lemmas have been added
+ class BoundInstTrie
+ {
+ public:
+ std::map< Node, BoundInstTrie > d_children;
+ bool hasInstantiated( std::vector< Node > & vals, int index = 0, bool madeNew = false ){
+ if( index>=(int)vals.size() ){
+ return !madeNew;
+ }else{
+ Node n = vals[index];
+ if( d_children.find(n)==d_children.end() ){
+ madeNew = true;
+ }
+ return d_children[n].hasInstantiated(vals,index+1,madeNew);
+ }
+ }
+ };
+ std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it;
+private:
+ void addLiteralFromRange( Node lit, Node r );
+public:
+ BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
+
+ void check( Theory::Effort e );
+ void registerQuantifier( Node f );
+ void assertNode( Node n );
+ Node getNextDecisionRequest();
+ bool isBoundVar( Node f, Node v ) { return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end(); }
+ unsigned getNumBoundVars( Node f ) { return d_set[f].size(); }
+ Node getBoundVar( Node f, int i ) { return d_set[f][i]; }
+ int getBoundVarNum( Node f, int i ) { return d_set_nums[f][i]; }
+ Node getLowerBound( Node f, Node v ){ return d_bounds[0][f][v]; }
+ Node getUpperBound( Node f, Node v ){ return d_bounds[1][f][v]; }
+ void getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
+ void getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
+ bool isGroundRange(Node f, Node v);
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 0c423de19..42b49cf01 100644
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -27,7 +27,7 @@ using namespace CVC4::theory;
using namespace CVC4::theory::inst;
bool CandidateGenerator::isLegalCandidate( Node n ){
- return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute()) ) );
+ return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) ) );
}
void CandidateGeneratorQueue::addCandidate( Node n ) {
@@ -149,7 +149,7 @@ void CandidateGeneratorQELitEq::reset( Node eqc ){
d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() );
}
Node CandidateGeneratorQELitEq::getNextCandidate(){
- while( d_eq.isFinished() ){
+ while( !d_eq.isFinished() ){
Node n = (*d_eq);
++d_eq;
if( n.getType()==d_match_pattern[0].getType() ){
@@ -186,3 +186,29 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){
}
return Node::null();
}
+
+
+CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
+ d_match_pattern( mpat ), d_qe( qe ){
+
+}
+
+void CandidateGeneratorQEAll::resetInstantiationRound() {
+
+}
+
+void CandidateGeneratorQEAll::reset( Node eqc ) {
+ d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() );
+}
+
+Node CandidateGeneratorQEAll::getNextCandidate() {
+ while( !d_eq.isFinished() ){
+ Node n = (*d_eq);
+ ++d_eq;
+ if( n.getType()==d_match_pattern.getType() ){
+ //an equivalence class with the same type as the pattern, return it
+ return n;
+ }
+ }
+ return Node::null();
+}
diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h
index 81b98ce0a..402a29848 100644
--- a/src/theory/quantifiers/candidate_generator.h
+++ b/src/theory/quantifiers/candidate_generator.h
@@ -69,8 +69,7 @@ public:
Node getNextCandidate();
};/* class CandidateGeneratorQueue */
-class CandidateGeneratorQEDisequal;
-
+//the default generator
class CandidateGeneratorQE : public CandidateGenerator
{
friend class CandidateGeneratorQEDisequal;
@@ -93,27 +92,6 @@ public:
Node getNextCandidate();
};
-
-//class CandidateGeneratorQEDisequal : public CandidateGenerator
-//{
-//private:
-// //equivalence class
-// Node d_eq_class;
-// //equivalence class info
-// EqClassInfo* d_eci;
-// //equivalence class iterator
-// EqClassInfo::BoolMap::const_iterator d_eqci_iter;
-// //instantiator pointer
-// QuantifiersEngine* d_qe;
-//public:
-// CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc );
-// ~CandidateGeneratorQEDisequal(){}
-//
-// void resetInstantiationRound();
-// void reset( Node eqc ); //should be what you want to be disequal from
-// Node getNextCandidate();
-//};
-
class CandidateGeneratorQELitEq : public CandidateGenerator
{
private:
@@ -150,6 +128,24 @@ public:
Node getNextCandidate();
};
+class CandidateGeneratorQEAll : public CandidateGenerator
+{
+private:
+ //the equality classes iterator
+ eq::EqClassesIterator d_eq;
+ //equality you are trying to match equalities for
+ Node d_match_pattern;
+ //einstantiator pointer
+ QuantifiersEngine* d_qe;
+public:
+ CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat );
+ ~CandidateGeneratorQEAll(){}
+
+ void resetInstantiationRound();
+ void reset( Node eqc );
+ Node getNextCandidate();
+};
+
}/* CVC4::theory::inst namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index bba9c0163..63cac9c15 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -25,6 +25,7 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::quantifiers::fmcheck;
FirstOrderModel::FirstOrderModel( context::Context* c, std::string name ) : TheoryModel( c, name, true ),
d_axiom_asserted( c, false ), d_forall_asserts( c ), d_isModelSet( c, false ){
@@ -38,15 +39,34 @@ void FirstOrderModel::assertQuantifier( Node n ){
}
}
-void FirstOrderModel::reset(){
- TheoryModel::reset();
+Node FirstOrderModel::getCurrentModelValue( Node n, bool partial ) {
+ std::vector< Node > children;
+ if( n.getNumChildren()>0 ){
+ if( n.getKind()!=APPLY_UF && n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ for (unsigned i=0; i<n.getNumChildren(); i++) {
+ Node nc = getCurrentModelValue( n[i], partial );
+ if (nc.isNull()) {
+ return Node::null();
+ }else{
+ children.push_back( nc );
+ }
+ }
+ if( n.getKind()==APPLY_UF ){
+ return getCurrentUfModelValue( n, children, partial );
+ }else{
+ Node nn = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ nn = Rewriter::rewrite( nn );
+ return nn;
+ }
+ }else{
+ return getRepresentative(n);
+ }
}
-void FirstOrderModel::initialize( bool considerAxioms ){
- //rebuild models
- d_uf_model_tree.clear();
- d_uf_model_gen.clear();
- d_array_model.clear();
+void FirstOrderModel::initialize( bool considerAxioms ) {
+ processInitialize();
//this is called after representatives have been chosen and the equality engine has been built
//for each quantifier, collect all operators we care about
for( int i=0; i<getNumAssertedQuantifiers(); i++ ){
@@ -59,6 +79,23 @@ void FirstOrderModel::initialize( bool considerAxioms ){
}
void FirstOrderModel::initializeModelForTerm( Node n ){
+ processInitializeModelForTerm( n );
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ initializeModelForTerm( n[i] );
+ }
+}
+
+FirstOrderModelIG::FirstOrderModelIG(context::Context* c, std::string name) : FirstOrderModel(c,name) {
+
+}
+
+void FirstOrderModelIG::processInitialize(){
+ //rebuild models
+ d_uf_model_tree.clear();
+ d_uf_model_gen.clear();
+}
+
+void FirstOrderModelIG::processInitializeModelForTerm( Node n ){
if( n.getKind()==APPLY_UF ){
Node op = n.getOperator();
if( d_uf_model_tree.find( op )==d_uf_model_tree.end() ){
@@ -82,14 +119,11 @@ void FirstOrderModel::initializeModelForTerm( Node n ){
}
}
*/
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- initializeModelForTerm( n[i] );
- }
}
//for evaluation of quantifier bodies
-void FirstOrderModel::resetEvaluate(){
+void FirstOrderModelIG::resetEvaluate(){
d_eval_uf_use_default.clear();
d_eval_uf_model.clear();
d_eval_term_index_order.clear();
@@ -107,7 +141,7 @@ void FirstOrderModel::resetEvaluate(){
// if eVal = 0, then n' cannot be proven to be equal to phaseReq
// if eVal is not 0, then
// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
-int FirstOrderModel::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
+int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
++d_eval_formulas;
//Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
//Notice() << "Eval " << n << std::endl;
@@ -226,7 +260,7 @@ int FirstOrderModel::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
}
}
-Node FirstOrderModel::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
+Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
//Message() << "Eval term " << n << std::endl;
Node val;
depIndex = ri->getNumTerms()-1;
@@ -342,7 +376,7 @@ Node FirstOrderModel::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
return val;
}
-Node FirstOrderModel::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){
+Node FirstOrderModelIG::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){
depIndex = -1;
if( n.getNumChildren()==0 ){
return n;
@@ -372,14 +406,14 @@ Node FirstOrderModel::evaluateTermDefault( Node n, int& depIndex, std::vector< i
}
}
-void FirstOrderModel::clearEvalFailed( int index ){
+void FirstOrderModelIG::clearEvalFailed( int index ){
for( int i=0; i<(int)d_eval_failed_lits[index].size(); i++ ){
d_eval_failed[ d_eval_failed_lits[index][i] ] = false;
}
d_eval_failed_lits[index].clear();
}
-void FirstOrderModel::makeEvalUfModel( Node n ){
+void FirstOrderModelIG::makeEvalUfModel( Node n ){
if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){
makeEvalUfIndexOrder( n );
if( !d_eval_uf_use_default[n] ){
@@ -397,7 +431,7 @@ struct sortGetMaxVariableNum {
int computeMaxVariableNum( Node n ){
if( n.getKind()==INST_CONSTANT ){
return n.getAttribute(InstVarNumAttribute());
- }else if( n.hasAttribute(InstConstantAttribute()) ){
+ }else if( TermDb::hasInstConstAttr(n) ){
int maxVal = -1;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
int val = getMaxVariableNum( n[i] );
@@ -423,7 +457,7 @@ struct sortGetMaxVariableNum {
bool operator() (Node i,Node j) { return (getMaxVariableNum(i)<getMaxVariableNum(j));}
};
-void FirstOrderModel::makeEvalUfIndexOrder( Node n ){
+void FirstOrderModelIG::makeEvalUfIndexOrder( Node n ){
if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
#ifdef USE_INDEX_ORDERING
//sort arguments in order of least significant vs. most significant variable in default ordering
@@ -460,3 +494,187 @@ void FirstOrderModel::makeEvalUfIndexOrder( Node n ){
#endif
}
}
+
+Node FirstOrderModelIG::getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) {
+ std::vector< Node > children;
+ children.push_back(n.getOperator());
+ children.insert(children.end(), args.begin(), args.end());
+ Node nv = NodeManager::currentNM()->mkNode(APPLY_UF, children);
+ //make the term model specifically for nv
+ makeEvalUfModel( nv );
+ int argDepIndex;
+ if( d_eval_uf_use_default[nv] ){
+ return d_uf_model_tree[ n.getOperator() ].getValue( this, nv, argDepIndex );
+ }else{
+ return d_eval_uf_model[ nv ].getValue( this, nv, argDepIndex );
+ }
+}
+
+
+
+
+
+
+FirstOrderModelFmc::FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name) :
+FirstOrderModel(c, name), d_qe(qe){
+
+}
+
+Node FirstOrderModelFmc::getUsedRepresentative(Node n, bool strict) {
+ //Assert( fm->hasTerm(n) );
+ TypeNode tn = n.getType();
+ if( tn.isBoolean() ){
+ return areEqual(n, d_true) ? d_true : d_false;
+ }else{
+ if( !hasTerm(n) ){
+ if( strict ){
+ return Node::null();
+ }else{
+ Trace("fmc-warn") << "WARNING : no representative for " << n << std::endl;
+ }
+ }
+ Node r = getRepresentative(n);
+ if( d_model_basis_rep.find(tn)!=d_model_basis_rep.end() ){
+ if (r==d_model_basis_rep[tn]) {
+ r = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ }
+ }
+ return r;
+ }
+}
+
+Node FirstOrderModelFmc::getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) {
+ Trace("fmc-uf-model") << "Get model value for " << n << " " << n.getKind() << std::endl;
+ for(unsigned i=0; i<args.size(); i++) {
+ args[i] = getUsedRepresentative(args[i]);
+ }
+ Assert( n.getKind()==APPLY_UF );
+ return d_models[n.getOperator()]->evaluate(this, args);
+}
+
+void FirstOrderModelFmc::processInitialize() {
+ if( options::fmfFmcInterval() && intervalOp.isNull() ){
+ std::vector< TypeNode > types;
+ for(unsigned i=0; i<2; i++){
+ types.push_back(NodeManager::currentNM()->integerType());
+ }
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->integerType() );
+ intervalOp = NodeManager::currentNM()->mkSkolem( "interval_$$", typ, "op representing interval" );
+ }
+ for( std::map<Node, Def * >::iterator it = d_models.begin(); it != d_models.end(); ++it ){
+ it->second->reset();
+ }
+ d_model_basis_rep.clear();
+}
+
+void FirstOrderModelFmc::processInitializeModelForTerm(Node n) {
+ if( n.getKind()==APPLY_UF ){
+ if( d_models.find(n.getOperator())==d_models.end()) {
+ d_models[n.getOperator()] = new Def;
+ }
+ }
+}
+
+Node FirstOrderModelFmc::getSomeDomainElement(TypeNode tn){
+ //check if there is even any domain elements at all
+ if (!d_rep_set.hasType(tn)) {
+ Trace("fmc-model-debug") << "Must create domain element for " << tn << "..." << std::endl;
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ d_rep_set.d_type_reps[tn].push_back(mbt);
+ }else if( d_rep_set.d_type_reps[tn].size()==0 ){
+ Message() << "empty reps" << std::endl;
+ exit(0);
+ }
+ return d_rep_set.d_type_reps[tn][0];
+}
+
+
+bool FirstOrderModelFmc::isStar(Node n) {
+ return n==getStar(n.getType());
+}
+
+Node FirstOrderModelFmc::getStar(TypeNode tn) {
+ if( d_type_star.find(tn)==d_type_star.end() ){
+ Node st = NodeManager::currentNM()->mkSkolem( "star_$$", tn, "skolem created for full-model checking" );
+ d_type_star[tn] = st;
+ }
+ return d_type_star[tn];
+}
+
+Node FirstOrderModelFmc::getStarElement(TypeNode tn) {
+ Node st = getStar(tn);
+ if( options::fmfFmcInterval() && tn.isInteger() ){
+ st = getInterval( st, st );
+ }
+ return st;
+}
+
+bool FirstOrderModelFmc::isModelBasisTerm(Node n) {
+ return n==getModelBasisTerm(n.getType());
+}
+
+Node FirstOrderModelFmc::getModelBasisTerm(TypeNode tn) {
+ return d_qe->getTermDatabase()->getModelBasisTerm(tn);
+}
+
+Node FirstOrderModelFmc::getFunctionValue(Node op, const char* argPrefix ) {
+ Trace("fmc-model") << "Get function value for " << op << std::endl;
+ TypeNode type = op.getType();
+ std::vector< Node > vars;
+ for( size_t i=0; i<type.getNumChildren()-1; i++ ){
+ std::stringstream ss;
+ ss << argPrefix << (i+1);
+ Node b = NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] );
+ vars.push_back( b );
+ }
+ Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars);
+ Node curr;
+ for( int i=(d_models[op]->d_cond.size()-1); i>=0; i--) {
+ Node v = getRepresentative( d_models[op]->d_value[i] );
+ if( curr.isNull() ){
+ curr = v;
+ }else{
+ //make the condition
+ Node cond = d_models[op]->d_cond[i];
+ std::vector< Node > children;
+ for( unsigned j=0; j<cond.getNumChildren(); j++) {
+ if (isInterval(cond[j])){
+ if( !isStar(cond[j][0]) ){
+ children.push_back( NodeManager::currentNM()->mkNode( GEQ, vars[j], cond[j][0] ) );
+ }
+ if( !isStar(cond[j][1]) ){
+ children.push_back( NodeManager::currentNM()->mkNode( LT, vars[j], cond[j][1] ) );
+ }
+ }else if (!isStar(cond[j])){
+ Node c = getUsedRepresentative( cond[j] );
+ children.push_back( NodeManager::currentNM()->mkNode( EQUAL, vars[j], c ) );
+ }
+ }
+ Assert( !children.empty() );
+ Node cc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( AND, children );
+ curr = NodeManager::currentNM()->mkNode( ITE, cc, v, curr );
+ }
+ }
+ curr = Rewriter::rewrite( curr );
+ return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr);
+}
+
+bool FirstOrderModelFmc::isInterval(Node n) {
+ return n.getKind()==APPLY_UF && n.getOperator()==intervalOp;
+}
+
+Node FirstOrderModelFmc::getInterval( Node lb, Node ub ){
+ return NodeManager::currentNM()->mkNode( APPLY_UF, intervalOp, lb, ub );
+}
+
+bool FirstOrderModelFmc::isInRange( Node v, Node i ) {
+ for( unsigned b=0; b<2; b++ ){
+ if( !isStar( i[b] ) ){
+ if( ( b==0 && i[b].getConst<Rational>() > v.getConst<Rational>() ) ||
+ ( b==1 && i[b].getConst<Rational>() <= v.getConst<Rational>() ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index 76f21e19c..f6e012660 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -19,7 +19,6 @@
#include "theory/model.h"
#include "theory/uf/theory_uf_model.h"
-#include "theory/arrays/theory_arrays_model.h"
namespace CVC4 {
namespace theory {
@@ -30,33 +29,22 @@ namespace quantifiers{
class TermDb;
+class FirstOrderModelIG;
+namespace fmcheck {
+ class FirstOrderModelFmc;
+}
+
class FirstOrderModel : public TheoryModel
{
private:
- //for initialize model
- void initializeModelForTerm( Node n );
/** whether an axiom is asserted */
context::CDO< bool > d_axiom_asserted;
/** list of quantifiers asserted in the current context */
context::CDList<Node> d_forall_asserts;
/** is model set */
context::CDO< bool > d_isModelSet;
-public: //for Theory UF:
- //models for each UF operator
- std::map< Node, uf::UfModelTree > d_uf_model_tree;
- //model generators
- std::map< Node, uf::UfModelTreeGenerator > d_uf_model_gen;
-private:
- //map from terms to the models used to calculate their value
- std::map< Node, bool > d_eval_uf_use_default;
- std::map< Node, uf::UfModelTree > d_eval_uf_model;
- void makeEvalUfModel( Node n );
- //index ordering to use for each term
- std::map< Node, std::vector< int > > d_eval_term_index_order;
- void makeEvalUfIndexOrder( Node n );
-public: //for Theory Arrays:
- //default value for each non-store array
- std::map< Node, arrays::ArrayModel > d_array_model;
+ /** get current model value */
+ virtual Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) = 0;
public: //for Theory Quantifiers:
/** assert quantifier */
void assertQuantifier( Node n );
@@ -66,19 +54,51 @@ public: //for Theory Quantifiers:
Node getAssertedQuantifier( int i ) { return d_forall_asserts[i]; }
/** bool axiom asserted */
bool isAxiomAsserted() { return d_axiom_asserted; }
+ /** initialize model for term */
+ void initializeModelForTerm( Node n );
+ virtual void processInitializeModelForTerm( Node n ) = 0;
public:
FirstOrderModel( context::Context* c, std::string name );
virtual ~FirstOrderModel(){}
- // reset the model
- void reset();
+ virtual FirstOrderModelIG * asFirstOrderModelIG() { return NULL; }
+ virtual fmcheck::FirstOrderModelFmc * asFirstOrderModelFmc() { return NULL; }
// initialize the model
void initialize( bool considerAxioms = true );
+ virtual void processInitialize() = 0;
/** mark model set */
void markModelSet() { d_isModelSet = true; }
/** is model set */
bool isModelSet() { return d_isModelSet; }
+ /** get current model value */
+ Node getCurrentModelValue( Node n, bool partial = false );
+};/* class FirstOrderModel */
+
+
+class FirstOrderModelIG : public FirstOrderModel
+{
+public: //for Theory UF:
+ //models for each UF operator
+ std::map< Node, uf::UfModelTree > d_uf_model_tree;
+ //model generators
+ std::map< Node, uf::UfModelTreeGenerator > d_uf_model_gen;
+private:
+ //map from terms to the models used to calculate their value
+ std::map< Node, bool > d_eval_uf_use_default;
+ std::map< Node, uf::UfModelTree > d_eval_uf_model;
+ void makeEvalUfModel( Node n );
+ //index ordering to use for each term
+ std::map< Node, std::vector< int > > d_eval_term_index_order;
+ void makeEvalUfIndexOrder( Node n );
+ /** get current model value */
+ Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
//the following functions are for evaluating quantifier bodies
public:
+ FirstOrderModelIG(context::Context* c, std::string name);
+ FirstOrderModelIG * asFirstOrderModelIG() { return this; }
+ // initialize the model
+ void processInitialize();
+ //for initialize model
+ void processInitializeModelForTerm( Node n );
/** reset evaluation */
void resetEvaluate();
/** evaluate functions */
@@ -97,7 +117,49 @@ private:
void clearEvalFailed( int index );
std::map< Node, bool > d_eval_failed;
std::map< int, std::vector< Node > > d_eval_failed_lits;
-};/* class FirstOrderModel */
+};
+
+
+namespace fmcheck {
+
+class Def;
+
+class FirstOrderModelFmc : public FirstOrderModel
+{
+ friend class FullModelChecker;
+private:
+ /** quant engine */
+ QuantifiersEngine * d_qe;
+ /** models for UF */
+ std::map<Node, Def * > d_models;
+ std::map<TypeNode, Node > d_model_basis_rep;
+ std::map<TypeNode, Node > d_type_star;
+ Node intervalOp;
+ Node getUsedRepresentative(Node n, bool strict = false);
+ /** get current model value */
+ Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
+ void processInitializeModelForTerm(Node n);
+public:
+ FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name);
+ FirstOrderModelFmc * asFirstOrderModelFmc() { return this; }
+ // initialize the model
+ void processInitialize();
+
+ Node getFunctionValue(Node op, const char* argPrefix );
+
+ bool isStar(Node n);
+ Node getStar(TypeNode tn);
+ Node getStarElement(TypeNode tn);
+ bool isModelBasisTerm(Node n);
+ Node getModelBasisTerm(TypeNode tn);
+ Node getSomeDomainElement(TypeNode tn);
+ bool isInterval(Node n);
+ Node getInterval( Node lb, Node ub );
+ bool isInRange( Node v, Node i );
+};
+
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/quantifiers/first_order_reasoning.cpp b/src/theory/quantifiers/first_order_reasoning.cpp
new file mode 100644
index 000000000..ebfb55f08
--- /dev/null
+++ b/src/theory/quantifiers/first_order_reasoning.cpp
@@ -0,0 +1,171 @@
+/********************* */
+/*! \file first_order_reasoning.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief first order reasoning module
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/first_order_reasoning.h"
+#include "theory/rewriter.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+
+
+void FirstOrderPropagation::collectLits( Node n, std::vector<Node> & lits ){
+ if( n.getKind()==FORALL ){
+ collectLits( n[1], lits );
+ }else if( n.getKind()==OR ){
+ for(unsigned j=0; j<n.getNumChildren(); j++) {
+ collectLits(n[j], lits );
+ }
+ }else{
+ lits.push_back( n );
+ }
+}
+
+void FirstOrderPropagation::simplify( std::vector< Node >& assertions ){
+ for( unsigned i=0; i<assertions.size(); i++) {
+ Trace("fo-rsn") << "Assert : " << assertions[i] << std::endl;
+ }
+
+ //process all assertions
+ int num_processed;
+ int num_true = 0;
+ int num_rounds = 0;
+ do {
+ num_processed = 0;
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ if( d_assertion_true.find(assertions[i])==d_assertion_true.end() ){
+ std::vector< Node > fo_lits;
+ collectLits( assertions[i], fo_lits );
+ Node unitLit = process( assertions[i], fo_lits );
+ if( !unitLit.isNull() ){
+ Trace("fo-rsn-debug") << "...possible unit literal : " << unitLit << " from " << assertions[i] << std::endl;
+ bool pol = unitLit.getKind()!=NOT;
+ unitLit = unitLit.getKind()==NOT ? unitLit[0] : unitLit;
+ if( unitLit.getKind()==EQUAL ){
+
+ }else if( unitLit.getKind()==APPLY_UF ){
+ //make sure all are unique vars;
+ bool success = true;
+ std::vector< Node > unique_vars;
+ for( unsigned j=0; j<unitLit.getNumChildren(); j++) {
+ if( unitLit[j].getKind()==BOUND_VARIABLE ){
+ if( std::find(unique_vars.begin(), unique_vars.end(), unitLit[j])==unique_vars.end() ){
+ unique_vars.push_back( unitLit[j] );
+ }else{
+ success = false;
+ break;
+ }
+ }else{
+ success = false;
+ break;
+ }
+ }
+ if( success ){
+ d_const_def[unitLit.getOperator()] = NodeManager::currentNM()->mkConst(pol);
+ Trace("fo-rsn") << "Propagate : " << unitLit.getOperator() << " == " << pol << std::endl;
+ Trace("fo-rsn") << " from : " << assertions[i] << std::endl;
+ d_assertion_true[assertions[i]] = true;
+ num_processed++;
+ }
+ }else if( unitLit.getKind()==VARIABLE ){
+ d_const_def[unitLit] = NodeManager::currentNM()->mkConst(pol);
+ Trace("fo-rsn") << "Propagate variable : " << unitLit << " == " << pol << std::endl;
+ Trace("fo-rsn") << " from : " << assertions[i] << std::endl;
+ d_assertion_true[assertions[i]] = true;
+ num_processed++;
+ }
+ }
+ if( d_assertion_true.find(assertions[i])!=d_assertion_true.end() ){
+ num_true++;
+ }
+ }
+ }
+ num_rounds++;
+ }while( num_processed>0 );
+ Trace("fo-rsn-sum") << "Simplified " << num_true << " / " << assertions.size() << " in " << num_rounds << " rounds." << std::endl;
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ assertions[i] = theory::Rewriter::rewrite( simplify( assertions[i] ) );
+ }
+}
+
+Node FirstOrderPropagation::process(Node a, std::vector< Node > & lits) {
+ int index = -1;
+ for( unsigned i=0; i<lits.size(); i++) {
+ bool pol = lits[i].getKind()!=NOT;
+ Node n = lits[i].getKind()==NOT ? lits[i][0] : lits[i];
+ Node litDef;
+ if( n.getKind()==APPLY_UF ){
+ if( d_const_def.find(n.getOperator())!=d_const_def.end() ){
+ litDef = d_const_def[n.getOperator()];
+ }
+ }else if( n.getKind()==VARIABLE ){
+ if( d_const_def.find(n)!=d_const_def.end() ){
+ litDef = d_const_def[n];
+ }
+ }
+ if( !litDef.isNull() ){
+ Node poln = NodeManager::currentNM()->mkConst( pol );
+ if( litDef==poln ){
+ Trace("fo-rsn-debug") << "Assertion " << a << " is true because of " << lits[i] << std::endl;
+ d_assertion_true[a] = true;
+ return Node::null();
+ }
+ }
+ if( litDef.isNull() ){
+ if( index==-1 ){
+ //store undefined index
+ index = i;
+ }else{
+ //two undefined, return null
+ return Node::null();
+ }
+ }
+ }
+ if( index!=-1 ){
+ return lits[index];
+ }else{
+ return Node::null();
+ }
+}
+
+Node FirstOrderPropagation::simplify( Node n ) {
+ if( n.getKind()==VARIABLE ){
+ if( d_const_def.find(n)!=d_const_def.end() ){
+ return d_const_def[n];
+ }
+ }else if( n.getKind()==APPLY_UF ){
+ if( d_const_def.find(n.getOperator())!=d_const_def.end() ){
+ return d_const_def[n.getOperator()];
+ }
+ }
+ if( n.getNumChildren()==0 ){
+ return n;
+ }else{
+ std::vector< Node > children;
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ for(unsigned i=0; i<n.getNumChildren(); i++) {
+ children.push_back( simplify(n[i]) );
+ }
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+}
+
+}
diff --git a/src/theory/quantifiers/first_order_reasoning.h b/src/theory/quantifiers/first_order_reasoning.h
new file mode 100644
index 000000000..5f217050c
--- /dev/null
+++ b/src/theory/quantifiers/first_order_reasoning.h
@@ -0,0 +1,45 @@
+/********************* */
+/*! \file first_order_reasoning.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Pre-process step for first-order reasoning
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__FIRST_ORDER_REASONING_H
+#define __CVC4__FIRST_ORDER_REASONING_H
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+#include "expr/node.h"
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+class FirstOrderPropagation {
+private:
+ std::map< Node, Node > d_const_def;
+ std::map< Node, bool > d_assertion_true;
+ Node process(Node a, std::vector< Node > & lits);
+ void collectLits( Node n, std::vector<Node> & lits );
+ Node simplify( Node n );
+public:
+ FirstOrderPropagation(){}
+ ~FirstOrderPropagation(){}
+
+ void simplify( std::vector< Node >& assertions );
+};
+
+}
+
+#endif
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
new file mode 100644
index 000000000..bf10369e6
--- /dev/null
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -0,0 +1,1409 @@
+/********************* */
+/*! \file full_model_check.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of full model check class
+ **/
+
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/options.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::inst;
+using namespace CVC4::theory::quantifiers::fmcheck;
+
+struct ModelBasisArgSort
+{
+ std::vector< Node > d_terms;
+ bool operator() (int i,int j) {
+ return (d_terms[i].getAttribute(ModelBasisArgAttribute()) <
+ d_terms[j].getAttribute(ModelBasisArgAttribute()) );
+ }
+};
+
+
+struct ConstRationalSort
+{
+ std::vector< Node > d_terms;
+ bool operator() (int i, int j) {
+ return (d_terms[i].getConst<Rational>() < d_terms[j].getConst<Rational>() );
+ }
+};
+
+
+bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
+ if (index==(int)c.getNumChildren()) {
+ return d_data!=-1;
+ }else{
+ TypeNode tn = c[index].getType();
+ Node st = m->getStar(tn);
+ if(d_child.find(st)!=d_child.end()) {
+ if( d_child[st].hasGeneralization(m, c, index+1) ){
+ return true;
+ }
+ }
+ if( c[index]!=st && d_child.find( c[index] )!=d_child.end() ){
+ if( d_child[ c[index] ].hasGeneralization(m, c, index+1) ){
+ return true;
+ }
+ }
+ if( !options::fmfFmcInterval() || !c[index].getType().isInteger() ){
+ //for star: check if all children are defined and have generalizations
+ if( options::fmfFmcCoverSimplify() && c[index]==st ){
+ //check if all children exist and are complete
+ int num_child_def = d_child.size() - (d_child.find(st)!=d_child.end() ? 1 : 0);
+ if( num_child_def==m->d_rep_set.getNumRepresentatives(tn) ){
+ bool complete = true;
+ for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( !m->isStar(it->first) ){
+ if( !it->second.hasGeneralization(m, c, index+1) ){
+ complete = false;
+ break;
+ }
+ }
+ }
+ if( complete ){
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
+
+int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index ) {
+ Debug("fmc-entry-trie") << "Get generalization index " << inst.size() << " " << index << std::endl;
+ if (index==(int)inst.size()) {
+ return d_data;
+ }else{
+ int minIndex = -1;
+ if( options::fmfFmcInterval() && inst[index].getType().isInteger() ){
+ for( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( !m->isInterval( it->first ) ){
+ std::cout << "Not an interval during getGenIndex " << it->first << std::endl;
+ exit( 11 );
+ }
+ //check if it is in the range
+ if( m->isInRange(inst[index], it->first ) ){
+ int gindex = it->second.getGeneralizationIndex(m, inst, index+1);
+ if( minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
+ minIndex = gindex;
+ }
+ }
+ }
+ }else{
+ Node st = m->getStar(inst[index].getType());
+ if(d_child.find(st)!=d_child.end()) {
+ minIndex = d_child[st].getGeneralizationIndex(m, inst, index+1);
+ }
+ Node cc = inst[index];
+ if( cc!=st && d_child.find( cc )!=d_child.end() ){
+ int gindex = d_child[ cc ].getGeneralizationIndex(m, inst, index+1);
+ if (minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
+ minIndex = gindex;
+ }
+ }
+ }
+ return minIndex;
+ }
+}
+
+void EntryTrie::addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index ) {
+ if (index==(int)c.getNumChildren()) {
+ if(d_data==-1) {
+ d_data = data;
+ }
+ }
+ else {
+ d_child[ c[index] ].addEntry(m,c,v,data,index+1);
+ if( d_complete==0 ){
+ d_complete = -1;
+ }
+ }
+}
+
+void EntryTrie::getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index, bool is_gen ) {
+ if (index==(int)c.getNumChildren()) {
+ if( d_data!=-1) {
+ if( is_gen ){
+ gen.push_back(d_data);
+ }
+ compat.push_back(d_data);
+ }
+ }else{
+ if (m->isStar(c[index])) {
+ for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ it->second.getEntries(m, c, compat, gen, index+1, is_gen );
+ }
+ }else{
+ Node st = m->getStar(c[index].getType());
+ if(d_child.find(st)!=d_child.end()) {
+ d_child[st].getEntries(m, c, compat, gen, index+1, false);
+ }
+ if( d_child.find( c[index] )!=d_child.end() ){
+ d_child[ c[index] ].getEntries(m, c, compat, gen, index+1, is_gen);
+ }
+ }
+
+ }
+}
+
+void EntryTrie::collectIndices(Node c, int index, std::vector< int >& indices ) {
+ if (index==(int)c.getNumChildren()) {
+ if( d_data!=-1 ){
+ indices.push_back( d_data );
+ }
+ }else{
+ for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ it->second.collectIndices(c, index+1, indices );
+ }
+ }
+}
+
+bool EntryTrie::isComplete(FirstOrderModelFmc * m, Node c, int index) {
+ if( d_complete==-1 ){
+ d_complete = 1;
+ if (index<(int)c.getNumChildren()) {
+ Node st = m->getStar(c[index].getType());
+ if(d_child.find(st)!=d_child.end()) {
+ if (!d_child[st].isComplete(m, c, index+1)) {
+ d_complete = 0;
+ }
+ }else{
+ d_complete = 0;
+ }
+ }
+ }
+ return d_complete==1;
+}
+
+bool Def::addEntry( FirstOrderModelFmc * m, Node c, Node v) {
+ if (d_et.hasGeneralization(m, c)) {
+ Trace("fmc-debug") << "Already has generalization, skip." << std::endl;
+ return false;
+ }
+ int newIndex = (int)d_cond.size();
+ if (!d_has_simplified) {
+ std::vector<int> compat;
+ std::vector<int> gen;
+ d_et.getEntries(m, c, compat, gen);
+ for( unsigned i=0; i<compat.size(); i++) {
+ if( d_status[compat[i]]==status_unk ){
+ if( d_value[compat[i]]!=v ){
+ d_status[compat[i]] = status_non_redundant;
+ }
+ }
+ }
+ for( unsigned i=0; i<gen.size(); i++) {
+ if( d_status[gen[i]]==status_unk ){
+ if( d_value[gen[i]]==v ){
+ d_status[gen[i]] = status_redundant;
+ }
+ }
+ }
+ d_status.push_back( status_unk );
+ }
+ d_et.addEntry(m, c, v, newIndex);
+ d_cond.push_back(c);
+ d_value.push_back(v);
+ return true;
+}
+
+Node Def::evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
+ int gindex = d_et.getGeneralizationIndex(m, inst);
+ if (gindex!=-1) {
+ return d_value[gindex];
+ }else{
+ Trace("fmc-warn") << "Warning : evaluation came up null!" << std::endl;
+ return Node::null();
+ }
+}
+
+int Def::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
+ return d_et.getGeneralizationIndex(m, inst);
+}
+
+void Def::basic_simplify( FirstOrderModelFmc * m ) {
+ d_has_simplified = true;
+ std::vector< Node > cond;
+ cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
+ d_cond.clear();
+ std::vector< Node > value;
+ value.insert( value.end(), d_value.begin(), d_value.end() );
+ d_value.clear();
+ d_et.reset();
+ for (unsigned i=0; i<d_status.size(); i++) {
+ if( d_status[i]!=status_redundant ){
+ addEntry(m, cond[i], value[i]);
+ }
+ }
+ d_status.clear();
+}
+
+void Def::simplify(FullModelChecker * mc, FirstOrderModelFmc * m) {
+ basic_simplify( m );
+
+ //check if the last entry is not all star, if so, we can make the last entry all stars
+ if( !d_cond.empty() ){
+ bool last_all_stars = true;
+ Node cc = d_cond[d_cond.size()-1];
+ for( unsigned i=0; i<cc.getNumChildren(); i++ ){
+ if( !m->isInterval(cc[i]) && !m->isStar(cc[i]) ){
+ last_all_stars = false;
+ break;
+ }
+ }
+ if( !last_all_stars ){
+ Trace("fmc-cover-simplify") << "Need to modify last entry to be all stars." << std::endl;
+ Trace("fmc-cover-simplify") << "Before: " << std::endl;
+ debugPrint("fmc-cover-simplify",Node::null(), mc);
+ Trace("fmc-cover-simplify") << std::endl;
+ std::vector< Node > cond;
+ cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
+ d_cond.clear();
+ std::vector< Node > value;
+ value.insert( value.end(), d_value.begin(), d_value.end() );
+ d_value.clear();
+ d_et.reset();
+ d_has_simplified = false;
+ //change the last to all star
+ std::vector< Node > nc;
+ nc.push_back( cc.getOperator() );
+ for( unsigned j=0; j< cc.getNumChildren(); j++){
+ nc.push_back(m->getStarElement(cc[j].getType()));
+ }
+ cond[cond.size()-1] = NodeManager::currentNM()->mkNode( APPLY_UF, nc );
+ //re-add the entries
+ for (unsigned i=0; i<cond.size(); i++) {
+ addEntry(m, cond[i], value[i]);
+ }
+ Trace("fmc-cover-simplify") << "Finished re-adding entries." << std::endl;
+ basic_simplify( m );
+ Trace("fmc-cover-simplify") << "After: " << std::endl;
+ debugPrint("fmc-cover-simplify",Node::null(), mc);
+ Trace("fmc-cover-simplify") << std::endl;
+ }
+ }
+}
+
+void Def::debugPrint(const char * tr, Node op, FullModelChecker * m) {
+ if (!op.isNull()) {
+ Trace(tr) << "Model for " << op << " : " << std::endl;
+ }
+ for( unsigned i=0; i<d_cond.size(); i++) {
+ //print the condition
+ if (!op.isNull()) {
+ Trace(tr) << op;
+ }
+ m->debugPrintCond(tr, d_cond[i], true);
+ Trace(tr) << " -> ";
+ m->debugPrint(tr, d_value[i]);
+ Trace(tr) << std::endl;
+ }
+}
+
+
+FullModelChecker::FullModelChecker(context::Context* c, QuantifiersEngine* qe) :
+QModelBuilder( c, qe ){
+ d_true = NodeManager::currentNM()->mkConst(true);
+ d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+bool FullModelChecker::optBuildAtFullModel() {
+ //need to build after full model has taken effect if we are constructing interval models
+ // this is because we need to have a constant in all integer equivalence classes
+ return options::fmfFmcInterval();
+}
+
+void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
+ FirstOrderModelFmc * fm = ((FirstOrderModelFmc*)m)->asFirstOrderModelFmc();
+ if( fullModel==optBuildAtFullModel() ){
+ Trace("fmc") << "---Full Model Check reset() " << std::endl;
+ fm->initialize( d_considerAxioms );
+ d_quant_models.clear();
+ d_rep_ids.clear();
+ d_star_insts.clear();
+ //process representatives
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
+ it != fm->d_rep_set.d_type_reps.end(); ++it ){
+ if( it->first.isSort() ){
+ Trace("fmc") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(it->first);
+ Node rmbt = fm->getUsedRepresentative( mbt);
+ int mbt_index = -1;
+ Trace("fmc") << " Model basis term : " << mbt << std::endl;
+ for( size_t a=0; a<it->second.size(); a++ ){
+ Node r = fm->getUsedRepresentative( it->second[a] );
+ std::vector< Node > eqc;
+ ((EqualityQueryQuantifiersEngine*)d_qe->getEqualityQuery())->getEquivalenceClass( r, eqc );
+ Trace("fmc-model-debug") << " " << (it->second[a]==r) << (r==mbt);
+ Trace("fmc-model-debug") << " : " << it->second[a] << " : " << r << " : ";
+ //Trace("fmc-model-debug") << r2 << " : " << ir << " : ";
+ Trace("fmc-model-debug") << " {";
+ //find best selection for representative
+ for( size_t i=0; i<eqc.size(); i++ ){
+ Trace("fmc-model-debug") << eqc[i] << ", ";
+ }
+ Trace("fmc-model-debug") << "}" << std::endl;
+
+ //if this is the model basis eqc, replace with actual model basis term
+ if (r==rmbt || (mbt_index==-1 && a==(it->second.size()-1))) {
+ fm->d_model_basis_rep[it->first] = r;
+ r = mbt;
+ mbt_index = a;
+ }
+ d_rep_ids[it->first][r] = (int)a;
+ }
+ Trace("fmc-model-debug") << std::endl;
+
+ if (mbt_index==-1) {
+ std::cout << " WARNING: model basis term is not a representative!" << std::endl;
+ exit(0);
+ }else{
+ Trace("fmc") << "Star index for " << it->first << " is " << mbt_index << std::endl;
+ }
+ }
+ }
+ //also process non-rep set sorts
+ for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ Node op = it->first;
+ TypeNode tno = op.getType();
+ for( unsigned i=0; i<tno.getNumChildren(); i++) {
+ initializeType( fm, tno[i] );
+ }
+ }
+ //now, make models
+ for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ Node op = it->first;
+ //reset the model
+ fm->d_models[op]->reset();
+
+ Trace("fmc-model-debug") << fm->d_uf_terms[op].size() << " model values for " << op << " ... " << std::endl;
+ for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+ Node r = fm->getUsedRepresentative(fm->d_uf_terms[op][i]);
+ Trace("fmc-model-debug") << fm->d_uf_terms[op][i] << " -> " << r << std::endl;
+ }
+ Trace("fmc-model-debug") << std::endl;
+
+
+ std::vector< Node > add_conds;
+ std::vector< Node > add_values;
+ bool needsDefault = true;
+ for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+ Node n = fm->d_uf_terms[op][i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ add_conds.push_back( n );
+ add_values.push_back( n );
+ }
+ }
+ //possibly get default
+ if( needsDefault ){
+ Node nmb = d_qe->getTermDatabase()->getModelBasisOpTerm(op);
+ //add default value if necessary
+ if( fm->hasTerm( nmb ) ){
+ Trace("fmc-model-debug") << "Add default " << nmb << std::endl;
+ add_conds.push_back( nmb );
+ add_values.push_back( nmb );
+ }else{
+ Node vmb = getSomeDomainElement(fm, nmb.getType());
+ Trace("fmc-model-debug") << "Add default to default representative " << nmb << " ";
+ Trace("fmc-model-debug") << fm->d_rep_set.d_type_reps[nmb.getType()].size() << std::endl;
+ add_conds.push_back( nmb );
+ add_values.push_back( vmb );
+ }
+ }
+
+ std::vector< Node > conds;
+ std::vector< Node > values;
+ std::vector< Node > entry_conds;
+ //get the entries for the mdoel
+ for( size_t i=0; i<add_conds.size(); i++ ){
+ Node c = add_conds[i];
+ Node v = add_values[i];
+ std::vector< Node > children;
+ std::vector< Node > entry_children;
+ children.push_back(op);
+ entry_children.push_back(op);
+ bool hasNonStar = false;
+ for( unsigned i=0; i<c.getNumChildren(); i++) {
+ Node ri = fm->getUsedRepresentative( c[i]);
+ if( !ri.getType().isSort() && !ri.isConst() ){
+ Trace("fmc-warn") << "Warning : model has non-constant argument in model " << ri << std::endl;
+ }
+ children.push_back(ri);
+ if( !options::fmfFmcInterval() || !ri.getType().isInteger() ){
+ if (fm->isModelBasisTerm(ri) ) {
+ ri = fm->getStar( ri.getType() );
+ }else{
+ hasNonStar = true;
+ }
+ }
+ entry_children.push_back(ri);
+ }
+ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Node nv = fm->getUsedRepresentative( v );
+ if( !nv.getType().isSort() && !nv.isConst() ){
+ Trace("fmc-warn") << "Warning : model has non-constant value in model " << nv << std::endl;
+ }
+ Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children );
+ if( std::find(conds.begin(), conds.end(), n )==conds.end() ){
+ Trace("fmc-model-debug") << "- add " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
+ conds.push_back(n);
+ values.push_back(nv);
+ entry_conds.push_back(en);
+ }
+ else {
+ Trace("fmc-model-debug") << "Already have entry for : " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
+ }
+ }
+
+
+ //sort based on # default arguments
+ std::vector< int > indices;
+ ModelBasisArgSort mbas;
+ for (int i=0; i<(int)conds.size(); i++) {
+ d_qe->getTermDatabase()->computeModelBasisArgAttribute( conds[i] );
+ mbas.d_terms.push_back(conds[i]);
+ indices.push_back(i);
+ }
+ std::sort( indices.begin(), indices.end(), mbas );
+
+ for (int i=0; i<(int)indices.size(); i++) {
+ fm->d_models[op]->addEntry(fm, entry_conds[indices[i]], values[indices[i]]);
+ }
+
+
+ if( options::fmfFmcInterval() ){
+ Trace("fmc-interval-model") << "Changing to interval model, Before : " << std::endl;
+ fm->d_models[op]->debugPrint("fmc-interval-model", op, this);
+ Trace("fmc-interval-model") << std::endl;
+ std::vector< int > indices;
+ for( int i=0; i<(int)fm->d_models[op]->d_cond.size(); i++ ){
+ indices.push_back( i );
+ }
+ std::map< int, std::map< int, Node > > changed_vals;
+ makeIntervalModel( fm, op, indices, 0, changed_vals );
+
+ std::vector< Node > conds;
+ std::vector< Node > values;
+ for( unsigned i=0; i<fm->d_models[op]->d_cond.size(); i++ ){
+ if( changed_vals.find(i)==changed_vals.end() ){
+ conds.push_back( fm->d_models[op]->d_cond[i] );
+ }else{
+ std::vector< Node > children;
+ children.push_back( op );
+ for( unsigned j=0; j<fm->d_models[op]->d_cond[i].getNumChildren(); j++ ){
+ if( changed_vals[i].find(j)==changed_vals[i].end() ){
+ children.push_back( fm->d_models[op]->d_cond[i][j] );
+ }else{
+ children.push_back( changed_vals[i][j] );
+ }
+ }
+ Node nc = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ conds.push_back( nc );
+ Trace("fmc-interval-model") << "Interval : Entry #" << i << " changed to ";
+ debugPrintCond("fmc-interval-model", nc, true );
+ Trace("fmc-interval-model") << std::endl;
+ }
+ values.push_back( fm->d_models[op]->d_value[i] );
+ }
+ fm->d_models[op]->reset();
+ for( unsigned i=0; i<conds.size(); i++ ){
+ fm->d_models[op]->addEntry(fm, conds[i], values[i] );
+ }
+ }
+
+ Trace("fmc-model-simplify") << "Before simplification : " << std::endl;
+ fm->d_models[op]->debugPrint("fmc-model-simplify", op, this);
+ Trace("fmc-model-simplify") << std::endl;
+
+ Trace("fmc-model-simplify") << "Simplifying " << op << "..." << std::endl;
+ fm->d_models[op]->simplify( this, fm );
+
+ fm->d_models[op]->debugPrint("fmc-model", op, this);
+ Trace("fmc-model") << std::endl;
+ }
+ }
+ if( fullModel ){
+ //make function values
+ for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ){
+ m->d_uf_models[ it->first ] = getFunctionValue( fm, it->first, "$x" );
+ }
+ TheoryEngineModelBuilder::processBuildModel( m, fullModel );
+ //mark that the model has been set
+ fm->markModelSet();
+ //debug the model
+ debugModel( fm );
+ }
+}
+
+void FullModelChecker::initializeType( FirstOrderModelFmc * fm, TypeNode tn ){
+ if( fm->d_model_basis_rep.find( tn )==fm->d_model_basis_rep.end() ){
+ Trace("fmc") << "Initialize type " << tn << " hasType = " << fm->d_rep_set.hasType(tn) << std::endl;
+ Node mbn;
+ if (!fm->d_rep_set.hasType(tn)) {
+ mbn = fm->getSomeDomainElement(tn);
+ }else{
+ mbn = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ }
+ Node mbnr = fm->getUsedRepresentative( mbn );
+ fm->d_model_basis_rep[tn] = mbnr;
+ Trace("fmc") << "Add model basis for type " << tn << " : " << mbn << " " << mbnr << std::endl;
+ }
+}
+
+void FullModelChecker::debugPrintCond(const char * tr, Node n, bool dispStar) {
+ Trace(tr) << "(";
+ for( unsigned j=0; j<n.getNumChildren(); j++) {
+ if( j>0 ) Trace(tr) << ", ";
+ debugPrint(tr, n[j], dispStar);
+ }
+ Trace(tr) << ")";
+}
+
+void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) {
+ FirstOrderModelFmc * fm = (FirstOrderModelFmc *)d_qe->getModel();
+ if( n.isNull() ){
+ Trace(tr) << "null";
+ }
+ else if(fm->isStar(n) && dispStar) {
+ Trace(tr) << "*";
+ }
+ else if(fm->isInterval(n)) {
+ debugPrint(tr, n[0], dispStar );
+ Trace(tr) << "...";
+ debugPrint(tr, n[1], dispStar );
+ }else{
+ TypeNode tn = n.getType();
+ if( d_rep_ids.find(tn)!=d_rep_ids.end() ){
+ if (d_rep_ids[tn].find(n)!=d_rep_ids[tn].end()) {
+ Trace(tr) << d_rep_ids[tn][n];
+ }else{
+ Trace(tr) << n;
+ }
+ }else{
+ Trace(tr) << n;
+ }
+ }
+}
+
+
+bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
+ Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl;
+ if( optUseModel() ){
+ FirstOrderModelFmc * fmfmc = fm->asFirstOrderModelFmc();
+ if (effort==0) {
+ //register the quantifier
+ if (d_quant_cond.find(f)==d_quant_cond.end()) {
+ std::vector< TypeNode > types;
+ for(unsigned i=0; i<f[0].getNumChildren(); i++){
+ types.push_back(f[0][i].getType());
+ d_quant_var_id[f][f[0][i]] = i;
+ }
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "fmc_$$", typ, "op created for full-model checking" );
+ d_quant_cond[f] = op;
+ }
+ //make sure all types are set
+ for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+ initializeType( fmfmc, f[0][i].getType() );
+ }
+
+ //model check the quantifier
+ doCheck(fmfmc, f, d_quant_models[f], f[1]);
+ Trace("fmc") << "Definition for quantifier " << f << " is : " << std::endl;
+ d_quant_models[f].debugPrint("fmc", Node::null(), this);
+ Trace("fmc") << std::endl;
+
+ //consider all entries going to non-true
+ for (unsigned i=0; i<d_quant_models[f].d_cond.size(); i++) {
+ if( d_quant_models[f].d_value[i]!=d_true) {
+ Trace("fmc-inst") << "Instantiate based on " << d_quant_models[f].d_cond[i] << "..." << std::endl;
+ bool hasStar = false;
+ std::vector< Node > inst;
+ for (unsigned j=0; j<d_quant_models[f].d_cond[i].getNumChildren(); j++) {
+ if (fmfmc->isStar(d_quant_models[f].d_cond[i][j])) {
+ hasStar = true;
+ inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j].getType()));
+ }else if( fmfmc->isInterval(d_quant_models[f].d_cond[i][j])){
+ hasStar = true;
+ //if interval, find a sample point
+ if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][0]) ){
+ if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][1]) ){
+ inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j][1].getType()));
+ }else{
+ Node nn = NodeManager::currentNM()->mkNode( MINUS, d_quant_models[f].d_cond[i][j][1],
+ NodeManager::currentNM()->mkConst( Rational(1) ) );
+ nn = Rewriter::rewrite( nn );
+ inst.push_back( nn );
+ }
+ }else{
+ inst.push_back(d_quant_models[f].d_cond[i][j][0]);
+ }
+ }else{
+ inst.push_back(d_quant_models[f].d_cond[i][j]);
+ }
+ }
+ bool addInst = true;
+ if( hasStar ){
+ //try obvious (specified by inst)
+ Node ev = d_quant_models[f].evaluate(fmfmc, inst);
+ if (ev==d_true) {
+ addInst = false;
+ }
+ }else{
+ //for debugging
+ if (Trace.isOn("fmc-test-inst")) {
+ Node ev = d_quant_models[f].evaluate(fmfmc, inst);
+ if( ev==d_true ){
+ std::cout << "WARNING: instantiation was true! " << f << " " << d_quant_models[f].d_cond[i] << std::endl;
+ exit(0);
+ }else{
+ Trace("fmc-test-inst") << "...instantiation evaluated to false." << std::endl;
+ }
+ }
+ }
+ if( addInst ){
+ InstMatch m;
+ for( unsigned j=0; j<inst.size(); j++) {
+ m.set( d_qe, f, j, inst[j] );
+ }
+ d_triedLemmas++;
+ if( d_qe->addInstantiation( f, m ) ){
+ Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
+ d_addedLemmas++;
+ }else{
+ Trace("fmc-debug-inst") << "** Instantiation was duplicate." << std::endl;
+ //this can happen if evaluation is unknown
+ //might try it next effort level
+ d_star_insts[f].push_back(i);
+ }
+ }else{
+ Trace("fmc-debug-inst") << "** Instantiation was already true." << std::endl;
+ //might try it next effort level
+ d_star_insts[f].push_back(i);
+ }
+ }
+ }
+ }else{
+ if (!d_star_insts[f].empty()) {
+ Trace("fmc-exh") << "Exhaustive instantiate " << f << std::endl;
+ Trace("fmc-exh") << "Definition was : " << std::endl;
+ d_quant_models[f].debugPrint("fmc-exh", Node::null(), this);
+ Trace("fmc-exh") << std::endl;
+ Def temp;
+ //simplify the exceptions?
+ for( int i=(d_star_insts[f].size()-1); i>=0; i--) {
+ //get witness for d_star_insts[f][i]
+ int j = d_star_insts[f][i];
+ if( temp.addEntry(fmfmc, d_quant_models[f].d_cond[j], d_quant_models[f].d_value[j] ) ){
+ if( !exhaustiveInstantiate(fmfmc, f, d_quant_models[f].d_cond[j], j ) ){
+ //something went wrong, resort to exhaustive instantiation
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index) {
+ RepSetIterator riter( d_qe, &(fm->d_rep_set) );
+ Trace("fmc-exh") << "Exhaustive instantiate based on index " << c_index << " : " << c << " ";
+ debugPrintCond("fmc-exh", c, true);
+ Trace("fmc-exh")<< std::endl;
+ Trace("fmc-exh-debug") << "Set interval domains..." << std::endl;
+ //set the bounds on the iterator based on intervals
+ for( unsigned i=0; i<c.getNumChildren(); i++ ){
+ if( c[i].getType().isInteger() ){
+ if( fm->isInterval(c[i]) ){
+ for( unsigned b=0; b<2; b++ ){
+ if( !fm->isStar(c[i][b]) ){
+ riter.d_bounds[b][i] = c[i][b];
+ }
+ }
+ }else if( !fm->isStar(c[i]) ){
+ riter.d_bounds[0][i] = c[i];
+ riter.d_bounds[1][i] = QuantArith::offset( c[i], 1 );
+ }
+ }
+ }
+ Trace("fmc-exh-debug") << "Set quantifier..." << std::endl;
+ //initialize
+ if( riter.setQuantifier( f ) ){
+ Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
+ //set the domains based on the entry
+ for (unsigned i=0; i<c.getNumChildren(); i++) {
+ if (riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS) {
+ TypeNode tn = c[i].getType();
+ if( d_rep_ids.find(tn)!=d_rep_ids.end() ){
+ if( fm->isInterval(c[i]) || fm->isStar(c[i]) ){
+ //add the full range
+ }else{
+ if (d_rep_ids[tn].find(c[i])!=d_rep_ids[tn].end()) {
+ riter.d_domain[i].clear();
+ riter.d_domain[i].push_back(d_rep_ids[tn][c[i]]);
+ }else{
+ return false;
+ }
+ }
+ }else{
+ return false;
+ }
+ }
+ }
+ int addedLemmas = 0;
+ //now do full iteration
+ while( !riter.isFinished() ){
+ d_triedLemmas++;
+ Trace("fmc-exh-debug") << "Inst : ";
+ std::vector< Node > inst;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ //m.set( d_quantEngine, f, riter.d_index_order[i], riter.getTerm( i ) );
+ Node r = fm->getUsedRepresentative( riter.getTerm( i ) );
+ debugPrint("fmc-exh-debug", r);
+ Trace("fmc-exh-debug") << " ";
+ inst.push_back(r);
+ }
+ int ev_index = d_quant_models[f].getGeneralizationIndex(fm, inst);
+ Trace("fmc-exh-debug") << ", index = " << ev_index << " / " << d_quant_models[f].d_value.size();
+ Node ev = ev_index==-1 ? Node::null() : d_quant_models[f].d_value[ev_index];
+ if (ev!=d_true) {
+ InstMatch m;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ m.set( d_qe, f, i, riter.getTerm( i ) );
+ }
+ Trace("fmc-exh-debug") << ", add!";
+ //add as instantiation
+ if( d_qe->addInstantiation( f, m ) ){
+ Trace("fmc-exh-debug") << " ...success.";
+ addedLemmas++;
+ }
+ }else{
+ Trace("fmc-exh-debug") << ", already true";
+ }
+ Trace("fmc-exh-debug") << std::endl;
+ int index = riter.increment();
+ Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
+ if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) {
+ Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
+ riter.increment2( index-1 );
+ }
+ }
+ d_addedLemmas += addedLemmas;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n ) {
+ Trace("fmc-debug") << "Check " << n << " " << n.getKind() << std::endl;
+ //first check if it is a bounding literal
+ if( n.hasAttribute(BoundIntLitAttribute()) ){
+ Trace("fmc-debug") << "It is a bounding literal, polarity = " << n.getAttribute(BoundIntLitAttribute()) << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), n.getAttribute(BoundIntLitAttribute())==1 ? d_false : d_true );
+ }else if( n.getKind() == kind::BOUND_VARIABLE ){
+ Trace("fmc-debug") << "Add default entry..." << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), n);
+ }
+ else if( n.getKind() == kind::NOT ){
+ //just do directly
+ doCheck( fm, f, d, n[0] );
+ doNegate( d );
+ }
+ else if( n.getKind() == kind::FORALL ){
+ d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+ }
+ else if( n.getType().isArray() ){
+ //make the definition
+ Node r = fm->getRepresentative(n);
+ Trace("fmc-debug") << "Representative for array is " << r << std::endl;
+ while( r.getKind() == kind::STORE ){
+ Node i = fm->getUsedRepresentative( r[1] );
+ Node e = fm->getUsedRepresentative( r[2] );
+ d.addEntry(fm, mkArrayCond(i), e );
+ r = fm->getRepresentative( r[0] );
+ }
+ Node defC = mkArrayCond(fm->getStar(n.getType().getArrayIndexType()));
+ bool success = false;
+ Node odefaultValue;
+ if( r.getKind() == kind::STORE_ALL ){
+ ArrayStoreAll storeAll = r.getConst<ArrayStoreAll>();
+ odefaultValue = Node::fromExpr(storeAll.getExpr());
+ Node defaultValue = fm->getUsedRepresentative( odefaultValue, true );
+ if( !defaultValue.isNull() ){
+ d.addEntry(fm, defC, defaultValue);
+ success = true;
+ }
+ }
+ if( !success ){
+ Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl;
+ Trace("fmc-warn") << " Default value was : " << odefaultValue << std::endl;
+ Trace("fmc-debug") << "Can't process base array " << r << std::endl;
+ //can't process this array
+ d.reset();
+ d.addEntry(fm, defC, Node::null());
+ }
+ }
+ else if( n.getNumChildren()==0 ){
+ Node r = n;
+ if( !n.isConst() ){
+ if( !fm->hasTerm(n) ){
+ r = getSomeDomainElement(fm, n.getType() );
+ }
+ r = fm->getUsedRepresentative( r );
+ }
+ Trace("fmc-debug") << "Add constant entry..." << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), r);
+ }
+ else{
+ std::vector< int > var_ch;
+ std::vector< Def > children;
+ for( int i=0; i<(int)n.getNumChildren(); i++) {
+ Def dc;
+ doCheck(fm, f, dc, n[i]);
+ children.push_back(dc);
+ if( n[i].getKind() == kind::BOUND_VARIABLE ){
+ var_ch.push_back(i);
+ }
+ }
+
+ if( n.getKind()==APPLY_UF ){
+ Trace("fmc-debug") << "Do uninterpreted compose " << n << std::endl;
+ //uninterpreted compose
+ doUninterpretedCompose( fm, f, d, n.getOperator(), children );
+ } else if( n.getKind()==SELECT ){
+ Trace("fmc-debug") << "Do select compose " << n << std::endl;
+ std::vector< Def > children2;
+ children2.push_back( children[1] );
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ std::vector< Node > val;
+ doUninterpretedCompose(fm, f, d, children[0], children2, 0, cond, val );
+ } else {
+ if( !var_ch.empty() ){
+ if( n.getKind()==EQUAL ){
+ if( var_ch.size()==2 ){
+ Trace("fmc-debug") << "Do variable equality " << n << std::endl;
+ doVariableEquality( fm, f, d, n );
+ }else{
+ Trace("fmc-debug") << "Do variable relation " << n << std::endl;
+ doVariableRelation( fm, f, d, var_ch[0]==0 ? children[1] : children[0], var_ch[0]==0 ? n[0] : n[1] );
+ }
+ }else{
+ Trace("fmc-warn") << "Don't know how to check " << n << std::endl;
+ d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+ }
+ }else{
+ Trace("fmc-debug") << "Do interpreted compose " << n << std::endl;
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ std::vector< Node > val;
+ //interpreted compose
+ doInterpretedCompose( fm, f, d, n, children, 0, cond, val );
+ }
+ }
+ Trace("fmc-debug") << "Simplify the definition..." << std::endl;
+ d.debugPrint("fmc-debug", Node::null(), this);
+ d.simplify(this, fm);
+ Trace("fmc-debug") << "Done simplifying" << std::endl;
+ }
+ Trace("fmc-debug") << "Definition for " << n << " is : " << std::endl;
+ d.debugPrint("fmc-debug", Node::null(), this);
+ Trace("fmc-debug") << std::endl;
+}
+
+void FullModelChecker::doNegate( Def & dc ) {
+ for (unsigned i=0; i<dc.d_cond.size(); i++) {
+ if (!dc.d_value[i].isNull()) {
+ dc.d_value[i] = dc.d_value[i]==d_true ? d_false : d_true;
+ }
+ }
+}
+
+void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq ) {
+ std::vector<Node> cond;
+ mkCondDefaultVec(fm, f, cond);
+ if (eq[0]==eq[1]){
+ d.addEntry(fm, mkCond(cond), d_true);
+ }else{
+ TypeNode tn = eq[0].getType();
+ if( tn.isSort() ){
+ int j = getVariableId(f, eq[0]);
+ int k = getVariableId(f, eq[1]);
+ if( !fm->d_rep_set.hasType( tn ) ){
+ getSomeDomainElement( fm, tn ); //to verify the type is initialized
+ }
+ for (unsigned i=0; i<fm->d_rep_set.d_type_reps[tn].size(); i++) {
+ Node r = fm->getUsedRepresentative( fm->d_rep_set.d_type_reps[tn][i] );
+ cond[j+1] = r;
+ cond[k+1] = r;
+ d.addEntry( fm, mkCond(cond), d_true);
+ }
+ d.addEntry( fm, mkCondDefault(fm, f), d_false);
+ }else{
+ d.addEntry( fm, mkCondDefault(fm, f), Node::null());
+ }
+ }
+}
+
+void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
+ int j = getVariableId(f, v);
+ for (unsigned i=0; i<dc.d_cond.size(); i++) {
+ Node val = dc.d_value[i];
+ if( val.isNull() ){
+ d.addEntry( fm, dc.d_cond[i], val);
+ }else{
+ if( dc.d_cond[i][j]!=val ){
+ if (fm->isStar(dc.d_cond[i][j])) {
+ std::vector<Node> cond;
+ mkCondVec(dc.d_cond[i],cond);
+ cond[j+1] = val;
+ d.addEntry(fm, mkCond(cond), d_true);
+ cond[j+1] = fm->getStar(val.getType());
+ d.addEntry(fm, mkCond(cond), d_false);
+ }else{
+ d.addEntry( fm, dc.d_cond[i], d_false);
+ }
+ }else{
+ d.addEntry( fm, dc.d_cond[i], d_true);
+ }
+ }
+ }
+}
+
+void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node op, std::vector< Def > & dc ) {
+ Trace("fmc-uf-debug") << "Definition : " << std::endl;
+ fm->d_models[op]->debugPrint("fmc-uf-debug", op, this);
+ Trace("fmc-uf-debug") << std::endl;
+
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ std::vector< Node > val;
+ doUninterpretedCompose( fm, f, d, *fm->d_models[op], dc, 0, cond, val);
+}
+
+void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
+ Def & df, std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val ) {
+ Trace("fmc-uf-process") << "process at " << index << std::endl;
+ for( unsigned i=1; i<cond.size(); i++) {
+ debugPrint("fmc-uf-process", cond[i], true);
+ Trace("fmc-uf-process") << " ";
+ }
+ Trace("fmc-uf-process") << std::endl;
+ if (index==(int)dc.size()) {
+ //we have an entry, now do actual compose
+ std::map< int, Node > entries;
+ doUninterpretedCompose2( fm, f, entries, 0, cond, val, df.d_et);
+ if( entries.empty() ){
+ d.addEntry(fm, mkCond(cond), Node::null());
+ }else{
+ //add them to the definition
+ for( unsigned e=0; e<df.d_cond.size(); e++ ){
+ if ( entries.find(e)!=entries.end() ){
+ Trace("fmf-uf-process-debug") << "Add entry..." << std::endl;
+ d.addEntry(fm, entries[e], df.d_value[e] );
+ Trace("fmf-uf-process-debug") << "Done add entry." << std::endl;
+ }
+ }
+ }
+ }else{
+ for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
+ if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
+ std::vector< Node > new_cond;
+ new_cond.insert(new_cond.end(), cond.begin(), cond.end());
+ if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
+ Trace("fmc-uf-process") << "index " << i << " succeeded meet." << std::endl;
+ val.push_back(dc[index].d_value[i]);
+ doUninterpretedCompose(fm, f, d, df, dc, index+1, new_cond, val);
+ val.pop_back();
+ }else{
+ Trace("fmc-uf-process") << "index " << i << " failed meet." << std::endl;
+ }
+ }
+ }
+ }
+}
+
+void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
+ std::map< int, Node > & entries, int index,
+ std::vector< Node > & cond, std::vector< Node > & val,
+ EntryTrie & curr ) {
+ Trace("fmc-uf-process") << "compose " << index << std::endl;
+ for( unsigned i=1; i<cond.size(); i++) {
+ debugPrint("fmc-uf-process", cond[i], true);
+ Trace("fmc-uf-process") << " ";
+ }
+ Trace("fmc-uf-process") << std::endl;
+ if (index==(int)val.size()) {
+ Node c = mkCond(cond);
+ Trace("fmc-uf-entry") << "Entry : " << c << " -> index[" << curr.d_data << "]" << std::endl;
+ entries[curr.d_data] = c;
+ }else{
+ Node v = val[index];
+ bool bind_var = false;
+ if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
+ int j = getVariableId(f, v);
+ Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
+ if (!fm->isStar(cond[j+1]) && !fm->isInterval(cond[j+1])) {
+ v = cond[j+1];
+ }else{
+ bind_var = true;
+ }
+ }
+ if (bind_var) {
+ Trace("fmc-uf-process") << "bind variable..." << std::endl;
+ int j = getVariableId(f, v);
+ if( fm->isStar(cond[j+1]) ){
+ for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+ cond[j+1] = it->first;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+ }
+ cond[j+1] = fm->getStar(v.getType());
+ }else{
+ Node orig = cond[j+1];
+ for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+ Node nw = doIntervalMeet( fm, it->first, orig );
+ if( !nw.isNull() ){
+ cond[j+1] = nw;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+ }
+ }
+ cond[j+1] = orig;
+ }
+ }else{
+ if( !v.isNull() ){
+ if( options::fmfFmcInterval() && v.getType().isInteger() ){
+ for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+ if( fm->isInRange( v, it->first ) ){
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+ }
+ }
+ }else{
+ if (curr.d_child.find(v)!=curr.d_child.end()) {
+ Trace("fmc-uf-process") << "follow value..." << std::endl;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[v]);
+ }
+ Node st = fm->getStarElement(v.getType());
+ if (curr.d_child.find(st)!=curr.d_child.end()) {
+ Trace("fmc-uf-process") << "follow star..." << std::endl;
+ doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[st]);
+ }
+ }
+ }
+ }
+ }
+}
+
+void FullModelChecker::doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
+ std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val ) {
+ if ( index==(int)dc.size() ){
+ Node c = mkCond(cond);
+ Node v = evaluateInterpreted(n, val);
+ d.addEntry(fm, c, v);
+ }
+ else {
+ TypeNode vtn = n.getType();
+ for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
+ if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
+ std::vector< Node > new_cond;
+ new_cond.insert(new_cond.end(), cond.begin(), cond.end());
+ if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
+ bool process = true;
+ if (vtn.isBoolean()) {
+ //short circuit
+ if( (n.getKind()==OR && dc[index].d_value[i]==d_true) ||
+ (n.getKind()==AND && dc[index].d_value[i]==d_false) ){
+ Node c = mkCond(new_cond);
+ d.addEntry(fm, c, dc[index].d_value[i]);
+ process = false;
+ }
+ }
+ if (process) {
+ val.push_back(dc[index].d_value[i]);
+ doInterpretedCompose(fm, f, d, n, dc, index+1, new_cond, val);
+ val.pop_back();
+ }
+ }
+ }
+ }
+ }
+}
+
+int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
+ Trace("fmc-debug3") << "isCompat " << c << std::endl;
+ Assert(cond.size()==c.getNumChildren()+1);
+ for (unsigned i=1; i<cond.size(); i++) {
+ if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ Node iv = doIntervalMeet( fm, cond[i], c[i-1], false );
+ if( iv.isNull() ){
+ return 0;
+ }
+ }else{
+ if( cond[i]!=c[i-1] && !fm->isStar(cond[i]) && !fm->isStar(c[i-1]) ) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
+ Trace("fmc-debug3") << "doMeet " << c << std::endl;
+ Assert(cond.size()==c.getNumChildren()+1);
+ for (unsigned i=1; i<cond.size(); i++) {
+ if( cond[i]!=c[i-1] ) {
+ if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ Node iv = doIntervalMeet( fm, cond[i], c[i-1] );
+ if( !iv.isNull() ){
+ cond[i] = iv;
+ }else{
+ return false;
+ }
+ }else{
+ if( fm->isStar(cond[i]) ){
+ cond[i] = c[i-1];
+ }else if( !fm->isStar(c[i-1]) ){
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+Node FullModelChecker::doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk ) {
+ if( fm->isStar( i1 ) ){
+ return i2;
+ }else if( fm->isStar( i2 ) ){
+ return i1;
+ }else{
+ if( !fm->isInterval( i1 ) || !fm->isInterval( i2 ) ){
+ std::cout << "Not interval during meet! " << i1 << " " << i2 << std::endl;
+ exit( 0 );
+ }
+ Node b[2];
+ for( unsigned j=0; j<2; j++ ){
+ Node b1 = i1[j];
+ Node b2 = i2[j];
+ if( fm->isStar( b1 ) ){
+ b[j] = b2;
+ }else if( fm->isStar( b2 ) ){
+ b[j] = b1;
+ }else if( b1.getConst<Rational>() < b2.getConst<Rational>() ){
+ b[j] = j==0 ? b2 : b1;
+ }else{
+ b[j] = j==0 ? b1 : b2;
+ }
+ }
+ if( fm->isStar( b[0] ) || fm->isStar( b[1] ) || b[0].getConst<Rational>() < b[1].getConst<Rational>() ){
+ return mk ? fm->getInterval( b[0], b[1] ) : i1;
+ }else{
+ return Node::null();
+ }
+ }
+}
+
+Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
+ return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
+}
+
+Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
+ std::vector< Node > cond;
+ mkCondDefaultVec(fm, f, cond);
+ return mkCond(cond);
+}
+
+void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
+ Trace("fmc-debug") << "Make default vec, intervals = " << options::fmfFmcInterval() << std::endl;
+ //get function symbol for f
+ cond.push_back(d_quant_cond[f]);
+ for (unsigned i=0; i<f[0].getNumChildren(); i++) {
+ Node ts = fm->getStarElement( f[0][i].getType() );
+ cond.push_back(ts);
+ }
+}
+
+void FullModelChecker::mkCondVec( Node n, std::vector< Node > & cond ) {
+ cond.push_back(n.getOperator());
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ cond.push_back( n[i] );
+ }
+}
+
+Node FullModelChecker::mkArrayCond( Node a ) {
+ if( d_array_term_cond.find(a)==d_array_term_cond.end() ){
+ if( d_array_cond.find(a.getType())==d_array_cond.end() ){
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( a.getType(), NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "fmc_$$", typ, "op created for full-model checking" );
+ d_array_cond[a.getType()] = op;
+ }
+ std::vector< Node > cond;
+ cond.push_back(d_array_cond[a.getType()]);
+ cond.push_back(a);
+ d_array_term_cond[a] = NodeManager::currentNM()->mkNode(APPLY_UF, cond );
+ }
+ return d_array_term_cond[a];
+}
+
+Node FullModelChecker::evaluateInterpreted( Node n, std::vector< Node > & vals ) {
+ if( n.getKind()==EQUAL ){
+ if (!vals[0].isNull() && !vals[1].isNull()) {
+ return vals[0]==vals[1] ? d_true : d_false;
+ }else{
+ return Node::null();
+ }
+ }else if( n.getKind()==ITE ){
+ if( vals[0]==d_true ){
+ return vals[1];
+ }else if( vals[0]==d_false ){
+ return vals[2];
+ }else{
+ return vals[1]==vals[2] ? vals[1] : Node::null();
+ }
+ }else if( n.getKind()==AND || n.getKind()==OR ){
+ bool isNull = false;
+ for (unsigned i=0; i<vals.size(); i++) {
+ if((vals[i]==d_true && n.getKind()==OR) || (vals[i]==d_false && n.getKind()==AND)) {
+ return vals[i];
+ }else if( vals[i].isNull() ){
+ isNull = true;
+ }
+ }
+ return isNull ? Node::null() : vals[0];
+ }else{
+ std::vector<Node> children;
+ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ for (unsigned i=0; i<vals.size(); i++) {
+ if( vals[i].isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( vals[i] );
+ }
+ }
+ Node nc = NodeManager::currentNM()->mkNode(n.getKind(), children);
+ Trace("fmc-eval") << "Evaluate " << nc << " to ";
+ nc = Rewriter::rewrite(nc);
+ Trace("fmc-eval") << nc << std::endl;
+ return nc;
+ }
+}
+
+Node FullModelChecker::getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn ) {
+ bool addRepId = !fm->d_rep_set.hasType( tn );
+ Node de = fm->getSomeDomainElement(tn);
+ if( addRepId ){
+ d_rep_ids[tn][de] = 0;
+ }
+ return de;
+}
+
+Node FullModelChecker::getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ) {
+ return fm->getFunctionValue(op, argPrefix);
+}
+
+
+bool FullModelChecker::useSimpleModels() {
+ return options::fmfFmcSimple();
+}
+
+void FullModelChecker::makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals ) {
+ if( index==(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
+ makeIntervalModel2( fm, op, indices, 0, changed_vals );
+ }else{
+ TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
+ if( tn.isInteger() ){
+ makeIntervalModel(fm,op,indices,index+1, changed_vals );
+ }else{
+ std::map< Node, std::vector< int > > new_indices;
+ for( unsigned i=0; i<indices.size(); i++ ){
+ Node v = fm->d_models[op]->d_cond[indices[i]][index];
+ new_indices[v].push_back( indices[i] );
+ }
+
+ for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
+ makeIntervalModel( fm, op, it->second, index+1, changed_vals );
+ }
+ }
+ }
+}
+
+void FullModelChecker::makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals ) {
+ Debug("fmc-interval-model-debug") << "Process " << index << " with indicies : ";
+ for( unsigned i=0; i<indices.size(); i++ ){
+ Debug("fmc-interval-model-debug") << indices[i] << " ";
+ }
+ Debug("fmc-interval-model-debug") << std::endl;
+
+ if( index<(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
+ TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
+ if( tn.isInteger() ){
+ std::map< Node, std::vector< int > > new_indices;
+ for( unsigned i=0; i<indices.size(); i++ ){
+ Node v = fm->d_models[op]->d_cond[indices[i]][index];
+ new_indices[v].push_back( indices[i] );
+ if( !v.isConst() ){
+ Trace("fmc-warn") << "WARNING: for interval, model has non-constant : " << v << std::endl;
+ Trace("fmc-warn") << "From condition : " << fm->d_models[op]->d_cond[indices[i]] << std::endl;
+ }
+ }
+
+ std::vector< Node > values;
+ for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
+ makeIntervalModel2( fm, op, it->second, index+1, changed_vals );
+ values.push_back( it->first );
+ }
+
+ if( tn.isInteger() ){
+ //sort values by size
+ ConstRationalSort crs;
+ std::vector< int > sindices;
+ for( unsigned i=0; i<values.size(); i++ ){
+ sindices.push_back( (int)i );
+ crs.d_terms.push_back( values[i] );
+ }
+ std::sort( sindices.begin(), sindices.end(), crs );
+
+ Node ub = fm->getStar( tn );
+ for( int i=(int)(sindices.size()-1); i>=0; i-- ){
+ Node lb = fm->getStar( tn );
+ if( i>0 ){
+ lb = values[sindices[i]];
+ }
+ Node interval = fm->getInterval( lb, ub );
+ for( unsigned j=0; j<new_indices[values[sindices[i]]].size(); j++ ){
+ Debug("fmc-interval-model-debug") << "Change " << new_indices[values[sindices[i]]][j] << ", " << index << " to " << interval << std::endl;
+ changed_vals[new_indices[values[sindices[i]]][j]][index] = interval;
+ }
+ ub = lb;
+ }
+ }
+ }else{
+ makeIntervalModel2( fm, op, indices, index+1, changed_vals );
+ }
+ }
+}
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
new file mode 100644
index 000000000..6bb375c34
--- /dev/null
+++ b/src/theory/quantifiers/full_model_check.h
@@ -0,0 +1,160 @@
+/********************* */
+/*! \file full_model_check.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Full model check class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef FULL_MODEL_CHECK
+#define FULL_MODEL_CHECK
+
+#include "theory/quantifiers/model_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+namespace fmcheck {
+
+
+class FirstOrderModelFmc;
+class FullModelChecker;
+
+class EntryTrie
+{
+private:
+ int d_complete;
+public:
+ EntryTrie() : d_complete(-1), d_data(-1){}
+ std::map<Node,EntryTrie> d_child;
+ int d_data;
+ void reset() { d_data = -1; d_child.clear(); d_complete = -1; }
+ void addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index = 0 );
+ bool hasGeneralization( FirstOrderModelFmc * m, Node c, int index = 0 );
+ int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index = 0 );
+ void getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index = 0, bool is_gen = true );
+
+ void collectIndices(Node c, int index, std::vector< int >& indices );
+ bool isComplete(FirstOrderModelFmc * m, Node c, int index);
+};
+
+
+class Def
+{
+public:
+ EntryTrie d_et;
+ //cond is APPLY_UF whose arguments are returned by FullModelChecker::getRepresentative
+ std::vector< Node > d_cond;
+ //value is returned by FullModelChecker::getRepresentative
+ std::vector< Node > d_value;
+ void basic_simplify( FirstOrderModelFmc * m );
+private:
+ enum {
+ status_unk,
+ status_redundant,
+ status_non_redundant
+ };
+ std::vector< int > d_status;
+ bool d_has_simplified;
+public:
+ Def() : d_has_simplified(false){}
+ void reset() {
+ d_et.reset();
+ d_cond.clear();
+ d_value.clear();
+ d_status.clear();
+ d_has_simplified = false;
+ }
+ bool addEntry( FirstOrderModelFmc * m, Node c, Node v);
+ Node evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst );
+ int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst );
+ void simplify( FullModelChecker * mc, FirstOrderModelFmc * m );
+ void debugPrint(const char * tr, Node op, FullModelChecker * m);
+};
+
+
+class FullModelChecker : public QModelBuilder
+{
+protected:
+ Node d_true;
+ Node d_false;
+ std::map<TypeNode, std::map< Node, int > > d_rep_ids;
+ std::map<Node, Def > d_quant_models;
+ std::map<Node, Node > d_quant_cond;
+ std::map< TypeNode, Node > d_array_cond;
+ std::map< Node, Node > d_array_term_cond;
+ std::map<Node, std::map< Node, int > > d_quant_var_id;
+ std::map<Node, std::vector< int > > d_star_insts;
+ void initializeType( FirstOrderModelFmc * fm, TypeNode tn );
+ Node normalizeArgReps(FirstOrderModelFmc * fm, Node op, Node n);
+ bool exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index);
+protected:
+ void makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals );
+ void makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+ std::map< int, std::map< int, Node > >& changed_vals );
+private:
+ void doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n );
+
+ void doNegate( Def & dc );
+ void doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq );
+ void doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v);
+ void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n, std::vector< Def > & dc );
+
+ void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
+ Def & df, std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val );
+ void doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
+ std::map< int, Node > & entries, int index,
+ std::vector< Node > & cond, std::vector< Node > & val,
+ EntryTrie & curr);
+
+ void doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
+ std::vector< Def > & dc, int index,
+ std::vector< Node > & cond, std::vector<Node> & val );
+ int isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
+ Node doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk = true );
+ bool doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
+ Node mkCond( std::vector< Node > & cond );
+ Node mkCondDefault( FirstOrderModelFmc * fm, Node f );
+ void mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond );
+ void mkCondVec( Node n, std::vector< Node > & cond );
+ Node mkArrayCond( Node a );
+ Node evaluateInterpreted( Node n, std::vector< Node > & vals );
+ Node getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn );
+public:
+ FullModelChecker( context::Context* c, QuantifiersEngine* qe );
+ ~FullModelChecker(){}
+
+ bool optBuildAtFullModel();
+
+ int getVariableId(Node f, Node n) { return d_quant_var_id[f][n]; }
+
+ void debugPrintCond(const char * tr, Node n, bool dispStar = false);
+ void debugPrint(const char * tr, Node n, bool dispStar = false);
+
+ bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
+
+ Node getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix );
+
+ /** process build model */
+ void processBuildModel(TheoryModel* m, bool fullModel);
+ /** get current model value */
+ Node getCurrentUfModelValue( FirstOrderModelFmc* fm, Node n, std::vector< Node > & args, bool partial );
+
+ bool useSimpleModels();
+};
+
+}
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp
index e495b39c0..157861670 100644
--- a/src/theory/quantifiers/inst_gen.cpp
+++ b/src/theory/quantifiers/inst_gen.cpp
@@ -29,10 +29,10 @@ using namespace CVC4::theory::quantifiers;
InstGenProcess::InstGenProcess( Node n ) : d_node( n ){
- Assert( n.hasAttribute(InstConstantAttribute()) );
+ Assert( TermDb::hasInstConstAttr(n) );
int count = 0;
for( size_t i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()!=INST_CONSTANT && TermDb::hasInstConstAttr(n[i]) ){
d_children.push_back( InstGenProcess( n[i] ) );
d_children_index.push_back( i );
d_children_map[ i ] = count;
@@ -47,7 +47,7 @@ void InstGenProcess::addMatchValue( QuantifiersEngine* qe, Node f, Node val, Ins
if( d_inst_trie[val].addInstMatch( qe, f, m, true ) ){
d_match_values.push_back( val );
d_matches.push_back( InstMatch( &m ) );
- qe->getModelEngine()->getModelBuilder()->d_instGenMatches++;
+ ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->d_instGenMatches++;
}
}
}
@@ -92,7 +92,7 @@ void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vecto
//for each term we consider, calculate a current match
for( size_t i=0; i<considerTerms.size(); i++ ){
Node n = considerTerms[i];
- bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n );
+ bool isSelected = ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->isTermSelected( n );
bool hadSuccess CVC4_UNUSED = false;
for( int t=(isSelected ? 0 : 1); t<2; t++ ){
if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
@@ -193,7 +193,7 @@ void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vecto
//process all values
for( size_t i=0; i<considerTerms.size(); i++ ){
Node n = considerTerms[i];
- bool isSelected = qe->getModelEngine()->getModelBuilder()->isTermSelected( n );
+ bool isSelected = ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->isTermSelected( n );
for( int t=(isSelected ? 0 : 1); t<2; t++ ){
//do not consider ground case if it is already congruent to another ground term
if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp
index f6a0dad11..d55f72a88 100644
--- a/src/theory/quantifiers/inst_match.cpp
+++ b/src/theory/quantifiers/inst_match.cpp
@@ -134,18 +134,27 @@ Node InstMatch::getValue( Node var ) const{
}
}
+Node InstMatch::get( QuantifiersEngine* qe, Node f, int i ) {
+ return get( qe->getTermDatabase()->getInstantiationConstant( f, i ) );
+}
+
void InstMatch::set(TNode var, TNode n){
Assert( !var.isNull() );
- if( !n.isNull() &&// For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations
- //var.getType() == n.getType()
- !n.getType().isSubtypeOf( var.getType() ) ){
- Trace("inst-match-warn") << var.getAttribute(InstConstantAttribute()) << std::endl;
- Trace("inst-match-warn") << var << " " << var.getType() << " " << n << " " << n.getType() << std::endl ;
- Assert(false);
+ if (Trace.isOn("inst-match-warn")) {
+ // For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations
+ if( !n.isNull() && !n.getType().isSubtypeOf( var.getType() ) ){
+ Trace("inst-match-warn") << quantifiers::TermDb::getInstConstAttr(var) << std::endl;
+ Trace("inst-match-warn") << var << " " << var.getType() << " " << n << " " << n.getType() << std::endl ;
+ }
}
+ Assert( n.isNull() || n.getType().isSubtypeOf( var.getType() ) );
d_map[var] = n;
}
+void InstMatch::set( QuantifiersEngine* qe, Node f, int i, TNode n ) {
+ set( qe->getTermDatabase()->getInstantiationConstant( f, i ), n );
+}
+
/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){
if( long(index)<long(f[0].getNumChildren()) && ( !imtio || long(index)<long(imtio->d_order.size()) ) ){
diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h
index 127f83c60..72447fd66 100644
--- a/src/theory/quantifiers/inst_match.h
+++ b/src/theory/quantifiers/inst_match.h
@@ -92,8 +92,11 @@ public:
void erase(Node node){ d_map.erase(node); }
/** get */
Node get( TNode var ) { return d_map[var]; }
+ Node get( QuantifiersEngine* qe, Node f, int i );
/** set */
void set(TNode var, TNode n);
+ void set( QuantifiersEngine* qe, Node f, int i, TNode n );
+ /** size */
size_t size(){ return d_map.size(); }
/* iterator */
std::map< Node, Node >::iterator begin(){ return d_map.begin(); };
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index de7f2f373..bf4bb15a6 100644
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -32,16 +32,16 @@ namespace inst {
InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){
d_active_add = false;
- Assert( pat.hasAttribute(InstConstantAttribute()) );
+ Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
d_pattern = pat;
d_match_pattern = pat;
d_next = NULL;
}
-void InstMatchGenerator::setActiveAdd(){
- d_active_add = true;
+void InstMatchGenerator::setActiveAdd(bool val){
+ d_active_add = val;
if( d_next!=NULL ){
- d_next->setActiveAdd();
+ d_next->setActiveAdd(val);
}
}
@@ -52,28 +52,43 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
//we want to add the children of the NOT
d_match_pattern = d_pattern[0];
}
- if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){
- if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){
- Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) );
- //swap sides
- Node pat = d_pattern;
- d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] );
- d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern;
- if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
- d_match_pattern = d_match_pattern[1];
- }else{
- d_match_pattern = d_pattern[0][0];
+ if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==GEQ ){
+ //make sure the matching portion of the equality is on the LHS of d_pattern
+ // and record what d_match_pattern is
+ if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[0]) ||
+ d_match_pattern[0].getKind()==INST_CONSTANT ){
+ if( d_match_pattern[1].getKind()!=INST_CONSTANT ){
+ Assert( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[1]) );
+ Node mp = d_match_pattern[1];
+ //swap sides
+ Node pat = d_pattern;
+ if(d_match_pattern.getKind()==GEQ){
+ d_pattern = NodeManager::currentNM()->mkNode( kind::GT, d_match_pattern[1], d_match_pattern[0] );
+ d_pattern = d_pattern.negate();
+ }else{
+ d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] );
+ }
+ d_pattern = pat.getKind()==NOT ? d_pattern.negate() : d_pattern;
+ d_match_pattern = mp;
}
- }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){
- Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) );
- if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
- d_match_pattern = d_match_pattern[0];
+ }else if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[1]) ||
+ d_match_pattern[1].getKind()==INST_CONSTANT ){
+ if( d_match_pattern[0].getKind()!=INST_CONSTANT ){
+ Assert( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[0]) );
+ if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
+ d_match_pattern = d_match_pattern[0];
+ }else if( d_match_pattern[1].getKind()==INST_CONSTANT ){
+ d_match_pattern = d_match_pattern[0];
+ }
}
}
}
+ Trace("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
+
+ //now, collect children of d_match_pattern
int childMatchPolicy = MATCH_GEN_DEFAULT;
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
if( d_match_pattern[i].getKind()!=INST_CONSTANT && !Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
InstMatchGenerator * cimg = new InstMatchGenerator( d_match_pattern[i], childMatchPolicy );
d_children.push_back( cimg );
@@ -83,10 +98,11 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
}
}
- Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
-
//create candidate generator
- if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
+ if( d_match_pattern.getKind()==INST_CONSTANT ){
+ d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern );
+ }
+ else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
//we will be producing candidates via literal matching heuristics
if( d_pattern.getKind()!=NOT ){
@@ -96,50 +112,40 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
//candidates will be all disequalities
d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
}
- }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){
+ }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF ||
+ d_pattern.getKind()==GEQ || d_pattern.getKind()==GT || d_pattern.getKind()==NOT ){
Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
if( d_pattern.getKind()==NOT ){
- Unimplemented("Disequal generator unimplemented");
+ if (d_pattern[0][1].getKind()!=INST_CONSTANT) {
+ Unimplemented("Disequal generator unimplemented");
+ }else{
+ d_eq_class = d_pattern[0][1];
+ }
}else{
- Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
- //we are matching only in a particular equivalence class
- d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
//store the equivalence class that we will call d_cg->reset( ... ) on
d_eq_class = d_pattern[1];
}
+ Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
+ //we are matching only in a particular equivalence class
+ d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
}else if( Trigger::isAtomicTrigger( d_match_pattern ) ){
- //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){
- //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl;
- //}
//we will be scanning lists trying to find d_match_pattern.getOperator()
d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
}else{
d_cg = new CandidateGeneratorQueue;
- if( !Trigger::isArithmeticTrigger( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){
- Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
- //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
- d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
- }else{
- Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl;
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
- }
- //we will treat this as match gen internal arithmetic
- d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC;
- }
+ Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
+ d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
}
}
}
/** get match (not modulo equality) */
bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
- << m << ")" << ", " << d_children.size() << std::endl;
+ Trace("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
+ << m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl;
Assert( !d_match_pattern.isNull() );
if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){
return true;
- }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){
- return getMatchArithmetic( t, m, qe );
}else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){
return false;
}else{
@@ -149,12 +155,12 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
InstMatch prev( &m );
//if t is null
Assert( !t.isNull() );
- Assert( !t.hasAttribute(InstConstantAttribute()) );
+ Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
Assert( t.getKind()==d_match_pattern.getKind() );
Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() );
//first, check if ground arguments are not equal, or a match is in conflict
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
Node vv = d_match_pattern[i];
Node tt = t[i];
@@ -164,24 +170,54 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
if( !m.setMatch( q, vv, tt ) ){
//match is in conflict
- Debug("matching-debug") << "Match in conflict " << tt << " and "
+ Trace("matching-debug") << "Match in conflict " << tt << " and "
<< vv << " because "
<< m.get(vv)
<< std::endl;
- Debug("matching-fail") << "Match fail: " << m.get(vv) << " and " << tt << std::endl;
+ Trace("matching-fail") << "Match fail: " << m.get(vv) << " and " << tt << std::endl;
success = false;
break;
}
}
}else{
if( !q->areEqual( d_match_pattern[i], t[i] ) ){
- Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
+ Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
//ground arguments are not equal
success = false;
break;
}
}
}
+ //for relational matching
+ if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){
+ //also must fit match to equivalence class
+ bool pol = d_pattern.getKind()!=NOT;
+ Node pat = d_pattern.getKind()==NOT ? d_pattern[0] : d_pattern;
+ Node t_match;
+ if( pol ){
+ if (pat.getKind()==GT) {
+ Node r = NodeManager::currentNM()->mkConst( Rational(-1) );
+ t_match = NodeManager::currentNM()->mkNode(PLUS, t, r);
+ }else{
+ t_match = t;
+ }
+ }else{
+ if(pat.getKind()==EQUAL) {
+ Node r = NodeManager::currentNM()->mkConst( Rational(1) );
+ t_match = NodeManager::currentNM()->mkNode(PLUS, t, r);
+ }else if( pat.getKind()==IFF ){
+ t_match = NodeManager::currentNM()->mkConst( !q->areEqual( NodeManager::currentNM()->mkConst(true), t ) );
+ }else if( pat.getKind()==GEQ ){
+ Node r = NodeManager::currentNM()->mkConst( Rational(1) );
+ t_match = NodeManager::currentNM()->mkNode(PLUS, t, r);
+ }else if( pat.getKind()==GT ){
+ t_match = t;
+ }
+ }
+ if( !t_match.isNull() && !m.setMatch( q, d_eq_class, t_match ) ){
+ success = false;
+ }
+ }
if( success ){
//now, fit children into match
//we will be requesting candidates for matching terms for each child
@@ -208,95 +244,45 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
}
-bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl;
- if( !d_arith_coeffs.empty() ){
- NodeBuilder<> tb(kind::PLUS);
- Node ic = Node::null();
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << it->first << " -> " << it->second << std::endl;
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- //see if we can choose this to set
- if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){
- ic = it->first;
- }
- }else{
- Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl;
- Node tm = m.get( it->first );
- if( !it->second.isNull() ){
- tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm );
- }
- tb << tm;
- }
- }else{
- tb << it->second;
- }
- }
- if( !ic.isNull() ){
- Node tm;
- if( tb.getNumChildren()==0 ){
- tm = t;
- }else{
- tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
- tm = NodeManager::currentNM()->mkNode( MINUS, t, tm );
- }
- if( !d_arith_coeffs[ ic ].isNull() ){
- Assert( !ic.getType().isInteger() );
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() );
- tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm );
- }
- m.set( ic, Rewriter::rewrite( tm ));
- //set the rest to zeros
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) );
- }
- }
- }
- Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl;
- return true;
- }else{
- return false;
- }
- }else{
- return false;
- }
-}
-
-
/** reset instantiation round */
void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
- if( d_match_pattern.isNull() ){
- for( int i=0; i<(int)d_children.size(); i++ ){
- d_children[i]->resetInstantiationRound( qe );
- }
- }else{
+ if( !d_match_pattern.isNull() ){
+ Trace("matching-debug2") << this << " reset instantiation round." << std::endl;
+ d_needsReset = true;
if( d_cg ){
d_cg->resetInstantiationRound();
}
}
+ if( d_next ){
+ d_next->resetInstantiationRound( qe );
+ }
}
void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
+ Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl;
if( !eqc.isNull() ){
d_eq_class = eqc;
}
//we have a specific equivalence class in mind
//we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term
//just look in equivalence class of the RHS
- d_cg->reset( d_eq_class );
+ d_cg->reset( d_eq_class.getKind()==INST_CONSTANT ? Node::null() : d_eq_class );
+ d_needsReset = false;
}
bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){
+ if( d_needsReset ){
+ Trace("matching") << "Reset not done yet, must do the reset..." << std::endl;
+ reset( d_eq_class.getKind()==INST_CONSTANT ? Node::null() : d_eq_class, qe );
+ }
m.d_matched = Node::null();
- //Debug("matching") << this << " " << d_pattern << " get next match 2 " << m << " in eq class " << d_eq_class << std::endl;
+ Trace("matching") << this << " " << d_match_pattern << " get next match " << m << " in eq class " << d_eq_class << std::endl;
bool success = false;
Node t;
do{
//get the next candidate term t
t = d_cg->getNextCandidate();
+ Trace("matching-debug2") << "Matching candidate : " << t << std::endl;
//if t not null, try to fit it into match m
if( !t.isNull() && t.getType()==d_match_pattern.getType() ){
success = getMatch( f, t, m, qe );
@@ -304,9 +290,9 @@ bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine*
}while( !success && !t.isNull() );
m.d_matched = t;
if( !success ){
- //Debug("matching") << this << " failed, reset " << d_eq_class << std::endl;
+ Trace("matching") << this << " failed, reset " << d_eq_class << std::endl;
//we failed, must reset
- reset( d_eq_class, qe );
+ reset( d_eq_class.getKind()==INST_CONSTANT ? Node::null() : d_eq_class, qe );
}
return success;
}
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index 4c954fa81..5d2128922 100644
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -44,13 +44,14 @@ public:
/** add ground term t, called when t is added to term db */
virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0;
/** set active add */
- virtual void setActiveAdd() {}
+ virtual void setActiveAdd( bool val ) {}
};/* class IMGenerator */
class CandidateGenerator;
class InstMatchGenerator : public IMGenerator {
private:
+ bool d_needsReset;
/** candidate generator */
CandidateGenerator* d_cg;
/** policy to use for matching */
@@ -72,12 +73,8 @@ public:
MATCH_GEN_DEFAULT = 0,
MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers
//others (internally used)
- MATCH_GEN_INTERNAL_ARITHMETIC,
MATCH_GEN_INTERNAL_ERROR,
};
-private:
- /** for arithmetic */
- bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe );
public:
/** get the match against ground term or formula t.
d_match_pattern and t should have the same shape.
@@ -108,7 +105,7 @@ public:
int addTerm( Node f, Node t, QuantifiersEngine* qe );
bool d_active_add;
- void setActiveAdd();
+ void setActiveAdd( bool val );
static InstMatchGenerator* mkInstMatchGenerator( Node pat, QuantifiersEngine* qe );
static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe );
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
index dbdf95613..4fe4072a3 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.cpp
+++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp
@@ -41,6 +41,19 @@ bool InstStrategySimplex::calculateShouldProcess( Node f ){
return false;
}
+void getInstantiationConstants( Node n, std::vector< Node >& ics ){
+ if( n.getKind()==INST_CONSTANT ){
+ if( std::find( ics.begin(), ics.end(), n )==ics.end() ){
+ ics.push_back( n );
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getInstantiationConstants( n[i], ics );
+ }
+ }
+}
+
+
void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){
Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl;
d_instRows.clear();
@@ -54,37 +67,69 @@ void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort
ArithVar x = *vi;
if( d_th->d_internal->d_partialModel.hasEitherBound( x ) ){
Node n = avnm.asNode(x);
- Node f;
- NodeBuilder<> t(kind::PLUS);
- if( n.getKind()==PLUS ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- addTermToRow( x, n[i], f, t );
+
+ //collect instantiation constants
+ std::vector< Node > ics;
+ getInstantiationConstants( n, ics );
+ for( unsigned i=0; i<ics.size(); i++ ){
+
+ NodeBuilder<> t(kind::PLUS);
+ if( n.getKind()==PLUS ){
+ for( int j=0; j<(int)n.getNumChildren(); j++ ){
+ addTermToRow( ics[i], x, n[j], t );
+ }
+ }else{
+ addTermToRow( ics[i], x, n, t );
}
- }else{
- addTermToRow( x, n, f, t );
- }
- if( f!=Node::null() ){
- d_instRows[f].push_back( x );
+ d_instRows[ics[i]].push_back( x );
//this theory has constraints from f
+ Node f = TermDb::getInstConstAttr(ics[i]);
Debug("quant-arith") << "Has constraints from " << f << std::endl;
//set that we should process it
d_quantActive[ f ] = true;
//set tableaux term
if( t.getNumChildren()==0 ){
- d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) );
+ d_tableaux_term[ics[i]][x] = NodeManager::currentNM()->mkConst( Rational(0) );
}else if( t.getNumChildren()==1 ){
- d_tableaux_term[x] = t.getChild( 0 );
+ d_tableaux_term[ics[i]][x] = t.getChild( 0 );
}else{
- d_tableaux_term[x] = t;
+ d_tableaux_term[ics[i]][x] = t;
}
}
}
}
//print debug
+ Debug("quant-arith-debug") << std::endl;
debugPrint( "quant-arith-debug" );
d_counter++;
}
+void InstStrategySimplex::addTermToRow( Node i, ArithVar x, Node n, NodeBuilder<>& t ){
+ if( n.getKind()==MULT ){
+ if( TermDb::hasInstConstAttr(n[1]) ){
+ if( n[1]==i ){
+ d_ceTableaux[i][x][ n[1] ] = n[0];
+ }else{
+ d_tableaux_ce_term[i][x][ n[1] ] = n[0];
+ }
+ }else{
+ d_tableaux[i][x][ n[1] ] = n[0];
+ t << n;
+ }
+ }else{
+ if( TermDb::hasInstConstAttr(n) ){
+ if( n==i ){
+ d_ceTableaux[i][x][ n ] = Node::null();
+ }else{
+ d_tableaux_ce_term[i][x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
+ }
+ }else{
+ d_tableaux[i][x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
+ t << n;
+ }
+ }
+}
+
int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
if( e<2 ){
return STATUS_UNFINISHED;
@@ -92,48 +137,51 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
//Notice() << f << std::endl;
//Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl;
//Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl;
- Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_instRows[f].size() << std::endl;
- for( int j=0; j<(int)d_instRows[f].size(); j++ ){
- ArithVar x = d_instRows[f][j];
- if( !d_ceTableaux[x].empty() ){
- Debug("quant-arith-simplex") << "Check row " << x << std::endl;
- //instantiation row will be A*e + B*t = beta,
- // where e is a vector of terms , and t is vector of ground terms.
- // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant
- // We will construct the term ( beta - B*t)/coeff to use for e_i.
- InstMatch m;
- //By default, choose the first instantiation constant to be e_i.
- Node var = d_ceTableaux[x].begin()->first;
- if( var.getType().isInteger() ){
- std::map< Node, Node >::iterator it = d_ceTableaux[x].begin();
- //try to find coefficent that is +/- 1
- while( !var.isNull() && !d_ceTableaux[x][var].isNull() && d_ceTableaux[x][var]!=d_negOne ){
- ++it;
- if( it==d_ceTableaux[x].end() ){
- var = Node::null();
- }else{
- var = it->first;
+ for( int i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){
+ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
+ Debug("quant-arith-simplex") << "InstStrategySimplex check " << ic << ", rows = " << d_instRows[ic].size() << std::endl;
+ for( int j=0; j<(int)d_instRows[ic].size(); j++ ){
+ ArithVar x = d_instRows[ic][j];
+ if( !d_ceTableaux[ic][x].empty() ){
+ Debug("quant-arith-simplex") << "Check row " << ic << " " << x << std::endl;
+ //instantiation row will be A*e + B*t = beta,
+ // where e is a vector of terms , and t is vector of ground terms.
+ // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant
+ // We will construct the term ( beta - B*t)/coeff to use for e_i.
+ InstMatch m;
+ //By default, choose the first instantiation constant to be e_i.
+ Node var = d_ceTableaux[ic][x].begin()->first;
+ if( var.getType().isInteger() ){
+ std::map< Node, Node >::iterator it = d_ceTableaux[ic][x].begin();
+ //try to find coefficent that is +/- 1
+ while( !var.isNull() && !d_ceTableaux[ic][x][var].isNull() && d_ceTableaux[ic][x][var]!=d_negOne ){
+ ++it;
+ if( it==d_ceTableaux[ic][x].end() ){
+ var = Node::null();
+ }else{
+ var = it->first;
+ }
}
+ //otherwise, try one that divides all ground term coefficients? DO_THIS
}
- //otherwise, try one that divides all ground term coefficients? DO_THIS
- }
- if( !var.isNull() ){
- Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl;
- doInstantiation( f, d_tableaux_term[x], x, m, var );
- }else{
- Debug("quant-arith-simplex") << "Could not find var." << std::endl;
+ if( !var.isNull() ){
+ Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl;
+ doInstantiation( f, ic, d_tableaux_term[ic][x], x, m, var );
+ }else{
+ Debug("quant-arith-simplex") << "Could not find var." << std::endl;
+ }
+ ////choose a new variable based on alternation strategy
+ //int index = d_counter%(int)d_th->d_ceTableaux[x].size();
+ //Node var;
+ //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
+ // if( index==0 ){
+ // var = it->first;
+ // break;
+ // }
+ // index--;
+ //}
+ //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var );
}
- ////choose a new variable based on alternation strategy
- //int index = d_counter%(int)d_th->d_ceTableaux[x].size();
- //Node var;
- //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
- // if( index==0 ){
- // var = it->first;
- // break;
- // }
- // index--;
- //}
- //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var );
}
}
}
@@ -141,34 +189,6 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
}
-void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){
- if( n.getKind()==MULT ){
- if( n[1].hasAttribute(InstConstantAttribute()) ){
- f = n[1].getAttribute(InstConstantAttribute());
- if( n[1].getKind()==INST_CONSTANT ){
- d_ceTableaux[x][ n[1] ] = n[0];
- }else{
- d_tableaux_ce_term[x][ n[1] ] = n[0];
- }
- }else{
- d_tableaux[x][ n[1] ] = n[0];
- t << n;
- }
- }else{
- if( n.hasAttribute(InstConstantAttribute()) ){
- f = n.getAttribute(InstConstantAttribute());
- if( n.getKind()==INST_CONSTANT ){
- d_ceTableaux[x][ n ] = Node::null();
- }else{
- d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
- }
- }else{
- d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
- t << n;
- }
- }
-}
-
void InstStrategySimplex::debugPrint( const char* c ){
ArithVariables& avnm = d_th->d_internal->d_partialModel;
ArithVariables::var_iterator vi, vend;
@@ -218,14 +238,17 @@ void InstStrategySimplex::debugPrint( const char* c ){
Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i );
}
Debug(c) << std::endl;
- Debug(c) << " Instantiation rows: ";
- for( int i=0; i<(int)d_instRows[f].size(); i++ ){
- if( i>0 ){
- Debug(c) << ", ";
+ for( int j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){
+ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
+ Debug(c) << " Instantiation rows for " << ic << " : ";
+ for( int i=0; i<(int)d_instRows[ic].size(); i++ ){
+ if( i>0 ){
+ Debug(c) << ", ";
+ }
+ Debug(c) << d_instRows[ic][i];
}
- Debug(c) << d_instRows[f][i];
+ Debug(c) << std::endl;
}
- Debug(c) << std::endl;
}
}
@@ -234,15 +257,15 @@ void InstStrategySimplex::debugPrint( const char* c ){
// t[e] is a vector of terms containing instantiation constants from f,
// and term is a ground term (c1*t1 + ... + cn*tn).
// We construct the term ( beta - term )/coeff to use as an instantiation for var.
-bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){
+bool InstStrategySimplex::doInstantiation( Node f, Node ic, Node term, ArithVar x, InstMatch& m, Node var ){
//first try +delta
- if( doInstantiation2( f, term, x, m, var ) ){
+ if( doInstantiation2( f, ic, term, x, m, var ) ){
++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith);
return true;
}else{
#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA
//otherwise try -delta
- if( doInstantiation2( f, term, x, m, var, true ) ){
+ if( doInstantiation2( f, ic, term, x, m, var, true ) ){
++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith_minus);
return true;
}else{
@@ -254,16 +277,16 @@ bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMa
}
}
-bool InstStrategySimplex::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){
+bool InstStrategySimplex::doInstantiation2( Node f, Node ic, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){
// make term ( beta - term )/coeff
Node beta = getTableauxValue( x, minus_delta );
Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term );
- if( !d_ceTableaux[x][var].isNull() ){
+ if( !d_ceTableaux[ic][x][var].isNull() ){
if( var.getType().isInteger() ){
- Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) );
- instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal );
+ Assert( d_ceTableaux[ic][x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) );
+ instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[ic][x][var], instVal );
}else{
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst<Rational>() );
+ Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[ic][x][var].getConst<Rational>() );
instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal );
}
}
@@ -327,81 +350,9 @@ int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){
Node InstStrategyDatatypesValue::getValueFor( Node n ){
//simply get the ground value for n in the current model, if it exists,
// or return an arbitrary ground term otherwise
- if( !n.hasAttribute(InstConstantAttribute()) ){
+ if( !TermDb::hasInstConstAttr(n) ){
return n;
}else{
return n;
}
- /* FIXME
-
- Debug("quant-datatypes-debug") << "get value for " << n << std::endl;
- if( !n.hasAttribute(InstConstantAttribute()) ){
- return n;
- }else{
- Assert( n.getType().isDatatype() );
- //check if in equivalence class with ground term
- Node rep = getRepresentative( n );
- Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl;
- if( !rep.hasAttribute(InstConstantAttribute()) ){
- return rep;
- }else{
- if( !n.getType().isDatatype() ){
- return n.getType().mkGroundTerm();
- }else{
- if( n.getKind()==APPLY_CONSTRUCTOR ){
- std::vector< Node > children;
- children.push_back( n.getOperator() );
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- children.push_back( getValueFor( n[i] ) );
- }
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }else{
- const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
- TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels;
- //otherwise, use which constructor the inst constant is current chosen to be
- if( labels->find( n )!=labels->end() ){
- TheoryDatatypes::EqList* lbl = (*labels->find( n )).second;
- int tIndex = -1;
- if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){
- Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl;
- tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr());
- }else{
- Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl;
- //must find a possible choice
- vector< bool > possibleCons;
- possibleCons.resize( dt.getNumConstructors(), true );
- for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) {
- Node leqn = (*j);
- possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false;
- }
- for( unsigned int j=0; j<possibleCons.size(); j++ ) {
- if( possibleCons[j] ){
- tIndex = j;
- break;
- }
- }
- }
- Assert( tIndex!=-1 );
- Node cons = Node::fromExpr( dt[ tIndex ].getConstructor() );
- Debug("quant-datatypes-debug") << n << " cons is " << cons << std::endl;
- std::vector< Node > children;
- children.push_back( cons );
- for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) {
- Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n );
- if( n.hasAttribute(InstConstantAttribute()) ){
- InstConstantAttribute ica;
- sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) );
- }
- Node snn = getValueFor( sn );
- children.push_back( snn );
- }
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }else{
- return n.getType().mkGroundTerm();
- }
- }
- }
- }
- }
- */
}
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h
index a45318489..821beeae0 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.h
+++ b/src/theory/quantifiers/inst_strategy_cbqi.h
@@ -49,19 +49,19 @@ private:
/** for each quantifier, simplex rows */
std::map< Node, std::vector< arith::ArithVar > > d_instRows;
/** tableaux */
- std::map< arith::ArithVar, Node > d_tableaux_term;
- std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux_ce_term;
- std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux;
+ std::map< Node, std::map< arith::ArithVar, Node > > d_tableaux_term;
+ std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_tableaux_ce_term;
+ std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_tableaux;
/** ce tableaux */
- std::map< arith::ArithVar, std::map< Node, Node > > d_ceTableaux;
+ std::map< Node, std::map< arith::ArithVar, std::map< Node, Node > > > d_ceTableaux;
/** get value */
Node getTableauxValue( Node n, bool minus_delta = false );
Node getTableauxValue( arith::ArithVar v, bool minus_delta = false );
/** do instantiation */
- bool doInstantiation( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var );
- bool doInstantiation2( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false );
+ bool doInstantiation( Node f, Node ic, Node term, arith::ArithVar x, InstMatch& m, Node var );
+ bool doInstantiation2( Node f, Node ic, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false );
/** add term to row */
- void addTermToRow( arith::ArithVar x, Node n, Node& f, NodeBuilder<>& t );
+ void addTermToRow( Node ic, arith::ArithVar x, Node n, NodeBuilder<>& t );
/** print debug */
void debugPrint( const char* c );
private:
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index 0e1266e0d..ef81d55a1 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -144,7 +144,11 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e )
}
if( gen ){
generateTriggers( f, effort, e, status );
+ if( d_auto_gen_trigger[f].empty() && f.getNumChildren()==2 ){
+ Trace("no-trigger") << "Could not find trigger for " << f << std::endl;
+ }
}
+
//if( e==4 ){
// d_processed_trigger.clear();
// d_quantEngine->getEqualityQuery()->setLiberal( true );
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 77df69456..628f8b14a 100644
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -92,7 +92,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
NodeBuilder<> nb(kind::OR);
nb << f << ceLit;
Node lem = nb;
- Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl;
+ Trace("cbqi") << "Counterexample lemma : " << lem << std::endl;
d_quantEngine->getOutputChannel().lemma( lem );
addedLemma = true;
}
@@ -197,7 +197,10 @@ void InstantiationEngine::check( Theory::Effort e ){
<< d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl;
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node n = d_quantEngine->getModel()->getAssertedQuantifier( i );
- if( options::cbqi() && hasAddedCbqiLemma( n ) ){
+ //it is not active if we have found the skolemized negation is unsat
+ if( n.hasAttribute(QRewriteRuleAttribute()) ){
+ d_quant_active[n] = false;
+ }else if( options::cbqi() && hasAddedCbqiLemma( n ) ){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( n );
bool active, value;
bool ceValue = false;
@@ -210,7 +213,9 @@ void InstantiationEngine::check( Theory::Effort e ){
d_quant_active[n] = active;
if( active ){
Debug("quantifiers") << " Active : " << n;
- quantActive = true;
+ if( !TermDb::hasInstConstAttr(n) ){
+ quantActive = true;
+ }
}else{
Debug("quantifiers") << " NOT active : " << n;
if( d_quantEngine->getValuation().isDecision( cel ) ){
@@ -226,14 +231,18 @@ void InstantiationEngine::check( Theory::Effort e ){
Debug("quantifiers") << ", ce is asserted";
}
Debug("quantifiers") << std::endl;
+ //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
}else{
d_quant_active[n] = true;
- quantActive = true;
+ if( !TermDb::hasInstConstAttr(n) ){
+ quantActive = true;
+ }
Debug("quantifiers") << " Active : " << n << ", no ce assigned." << std::endl;
}
Debug("quantifiers-relevance") << "Quantifier : " << n << std::endl;
Debug("quantifiers-relevance") << " Relevance : " << d_quantEngine->getQuantifierRelevance()->getRelevance( n ) << std::endl;
Debug("quantifiers") << " Relevance : " << d_quantEngine->getQuantifierRelevance()->getRelevance( n ) << std::endl;
+ Trace("inst-engine-debug") << "Process : " << n << " " << d_quant_active[n] << std::endl;
}
if( quantActive ){
bool addedLemmas = doInstantiationRound( e );
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 0b74cfc5e..5edf2de96 100644
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -18,7 +18,6 @@
#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_model.h"
#include "theory/uf/theory_uf_strong_solver.h"
-#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/model_builder.h"
@@ -33,6 +32,65 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+
+QModelBuilder::QModelBuilder( context::Context* c, QuantifiersEngine* qe ) :
+TheoryEngineModelBuilder( qe->getTheoryEngine() ), d_curr_model( c, NULL ), d_qe( qe ){
+ d_considerAxioms = true;
+}
+
+bool QModelBuilder::isQuantifierActive( Node f ) {
+ return !f.hasAttribute(QRewriteRuleAttribute());
+}
+
+
+bool QModelBuilder::optUseModel() {
+ return options::fmfModelBasedInst();
+}
+
+void QModelBuilder::debugModel( FirstOrderModel* fm ){
+ //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true
+ if( Trace.isOn("quant-model-warn") ){
+ Trace("quant-model-warn") << "Testing quantifier instantiations..." << std::endl;
+ int tests = 0;
+ int bad = 0;
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ std::vector< Node > vars;
+ for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
+ vars.push_back( f[0][j] );
+ }
+ RepSetIterator riter( d_qe, &(fm->d_rep_set) );
+ if( riter.setQuantifier( f ) ){
+ while( !riter.isFinished() ){
+ tests++;
+ std::vector< Node > terms;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ terms.push_back( riter.getTerm( i ) );
+ }
+ Node n = d_qe->getInstantiation( f, vars, terms );
+ Node val = fm->getValue( n );
+ if( val!=fm->d_true ){
+ Trace("quant-model-warn") << "******* Instantiation " << n << " for " << std::endl;
+ Trace("quant-model-warn") << " " << f << std::endl;
+ Trace("quant-model-warn") << " Evaluates to " << val << std::endl;
+ bad++;
+ }
+ riter.increment();
+ }
+ Trace("quant-model-warn") << "Tested " << tests << " instantiations";
+ if( bad>0 ){
+ Trace("quant-model-warn") << ", " << bad << " failed" << std::endl;
+ }
+ Trace("quant-model-warn") << "." << std::endl;
+ }else{
+ Trace("quant-model-warn") << "Warning: Could not test quantifier " << f << std::endl;
+ }
+ }
+ }
+}
+
+
+
bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){
if( argIndex<(int)n.getNumChildren() ){
Node r;
@@ -53,49 +111,25 @@ bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){
}
}
-ModelEngineBuilder::ModelEngineBuilder( context::Context* c, QuantifiersEngine* qe ) :
-TheoryEngineModelBuilder( qe->getTheoryEngine() ),
-d_qe( qe ), d_curr_model( c, NULL ){
- d_considerAxioms = true;
+
+QModelBuilderIG::QModelBuilderIG( context::Context* c, QuantifiersEngine* qe ) :
+QModelBuilder( c, qe ) {
+
}
-void ModelEngineBuilder::debugModel( FirstOrderModel* fm ){
- //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true
- if( Trace.isOn("quant-model-warn") ){
- for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node f = fm->getAssertedQuantifier( i );
- std::vector< Node > vars;
- for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
- vars.push_back( f[0][j] );
- }
- RepSetIterator riter( &(fm->d_rep_set) );
- riter.setQuantifier( f );
- while( !riter.isFinished() ){
- std::vector< Node > terms;
- for( int i=0; i<riter.getNumTerms(); i++ ){
- terms.push_back( riter.getTerm( i ) );
- }
- Node n = d_qe->getInstantiation( f, vars, terms );
- Node val = fm->getValue( n );
- if( val!=fm->d_true ){
- Trace("quant-model-warn") << "******* Instantiation " << n << " for " << std::endl;
- Trace("quant-model-warn") << " " << f << std::endl;
- Trace("quant-model-warn") << " Evaluates to " << val << std::endl;
- }
- riter.increment();
- }
- }
- }
+Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial ) {
+ return n;
}
-void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
- FirstOrderModel* fm = (FirstOrderModel*)m;
+void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
+ FirstOrderModel* f = (FirstOrderModel*)m;
+ FirstOrderModelIG* fm = f->asFirstOrderModelIG();
if( fullModel ){
Assert( d_curr_model==fm );
//update models
for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
it->second.update( fm );
- Trace("model-func") << "ModelEngineBuilder: Make function value from tree " << it->first << std::endl;
+ Trace("model-func") << "QModelBuilder: Make function value from tree " << it->first << std::endl;
//construct function values
fm->d_uf_models[ it->first ] = it->second.getFunctionValue( "$x" );
}
@@ -106,7 +140,6 @@ void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
debugModel( fm );
}else{
d_curr_model = fm;
- d_addedLemmas = 0;
d_didInstGen = false;
//reset the internal information
reset( fm );
@@ -186,12 +219,13 @@ void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
}
}
//construct the model if necessary
- if( d_addedLemmas==0 || optExhInstNonInstGenQuant() ){
+ if( d_addedLemmas==0 ){
//if no immediate exceptions, build the model
// this model will be an approximation that will need to be tested via exhaustive instantiation
Trace("model-engine-debug") << "Building model..." << std::endl;
//build model for UF
for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ Trace("model-engine-debug-uf") << "Building model for " << it->first << "..." << std::endl;
constructModelUf( fm, it->first );
}
/*
@@ -211,7 +245,7 @@ void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
}
}
-int ModelEngineBuilder::initializeQuantifier( Node f, Node fp ){
+int QModelBuilderIG::initializeQuantifier( Node f, Node fp ){
if( d_quant_basis_match_added.find( f )==d_quant_basis_match_added.end() ){
//create the basis match if necessary
if( d_quant_basis_match.find( f )==d_quant_basis_match.end() ){
@@ -254,17 +288,18 @@ int ModelEngineBuilder::initializeQuantifier( Node f, Node fp ){
return 0;
}
-void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
+void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
d_uf_model_constructed.clear();
//determine if any functions are constant
- for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ for( std::map< Node, uf::UfModelTree >::iterator it = fmig->d_uf_model_tree.begin(); it != fmig->d_uf_model_tree.end(); ++it ){
Node op = it->first;
TermArgBasisTrie tabt;
- for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
- Node n = fm->d_uf_terms[op][i];
+ for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
+ Node n = fmig->d_uf_terms[op][i];
//for calculating if op is constant
if( !n.getAttribute(NoMatchAttribute()) ){
- Node v = fm->getRepresentative( n );
+ Node v = fmig->getRepresentative( n );
if( i==0 ){
d_uf_prefs[op].d_const_val = v;
}else if( v!=d_uf_prefs[op].d_const_val ){
@@ -273,10 +308,10 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
}
}
//for calculating terms that we don't need to consider
- if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){
+ if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
if( !n.getAttribute(BasisNoMatchAttribute()) ){
//need to consider if it is not congruent modulo model basis
- if( !tabt.addTerm( fm, n ) ){
+ if( !tabt.addTerm( fmig, n ) ){
BasisNoMatchAttribute bnma;
n.setAttribute(bnma,true);
}
@@ -284,10 +319,10 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
}
}
if( !d_uf_prefs[op].d_const_val.isNull() ){
- fm->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
- fm->d_uf_model_gen[op].makeModel( fm, it->second );
+ fmig->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
+ fmig->d_uf_model_gen[op].makeModel( fmig, it->second );
Debug("fmf-model-cons") << "Function " << op << " is the constant function ";
- fm->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
+ fmig->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
Debug("fmf-model-cons") << std::endl;
d_uf_model_constructed[op] = true;
}else{
@@ -296,7 +331,7 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
}
}
-bool ModelEngineBuilder::hasConstantDefinition( Node n ){
+bool QModelBuilderIG::hasConstantDefinition( Node n ){
Node lit = n.getKind()==NOT ? n[0] : n;
if( lit.getKind()==APPLY_UF ){
Node op = lit.getOperator();
@@ -307,60 +342,141 @@ bool ModelEngineBuilder::hasConstantDefinition( Node n ){
return false;
}
-bool ModelEngineBuilder::optUseModel() {
- return options::fmfModelBasedInst();
-}
-
-bool ModelEngineBuilder::optInstGen(){
+bool QModelBuilderIG::optInstGen(){
return options::fmfInstGen();
}
-bool ModelEngineBuilder::optOneQuantPerRoundInstGen(){
+bool QModelBuilderIG::optOneQuantPerRoundInstGen(){
return options::fmfInstGenOneQuantPerRound();
}
-bool ModelEngineBuilder::optExhInstNonInstGenQuant(){
- return options::fmfNewInstGen();
-}
-
-void ModelEngineBuilder::setEffort( int effort ){
- d_considerAxioms = effort>=1;
-}
-
-ModelEngineBuilder::Statistics::Statistics():
- d_num_quants_init("ModelEngineBuilder::Number_Quantifiers", 0),
- d_num_partial_quants_init("ModelEngineBuilder::Number_Partial_Quantifiers", 0),
- d_init_inst_gen_lemmas("ModelEngineBuilder::Initialize_Inst_Gen_Lemmas", 0 ),
- d_inst_gen_lemmas("ModelEngineBuilder::Inst_Gen_Lemmas", 0 )
+QModelBuilderIG::Statistics::Statistics():
+ d_num_quants_init("QModelBuilderIG::Number_Quantifiers", 0),
+ d_num_partial_quants_init("QModelBuilderIG::Number_Partial_Quantifiers", 0),
+ d_init_inst_gen_lemmas("QModelBuilderIG::Initialize_Inst_Gen_Lemmas", 0 ),
+ d_inst_gen_lemmas("QModelBuilderIG::Inst_Gen_Lemmas", 0 ),
+ d_eval_formulas("QModelBuilderIG::Eval_Formulas", 0 ),
+ d_eval_uf_terms("QModelBuilderIG::Eval_Uf_Terms", 0 ),
+ d_eval_lits("QModelBuilderIG::Eval_Lits", 0 ),
+ d_eval_lits_unknown("QModelBuilderIG::Eval_Lits_Unknown", 0 )
{
StatisticsRegistry::registerStat(&d_num_quants_init);
StatisticsRegistry::registerStat(&d_num_partial_quants_init);
StatisticsRegistry::registerStat(&d_init_inst_gen_lemmas);
StatisticsRegistry::registerStat(&d_inst_gen_lemmas);
+ StatisticsRegistry::registerStat(&d_eval_formulas);
+ StatisticsRegistry::registerStat(&d_eval_uf_terms);
+ StatisticsRegistry::registerStat(&d_eval_lits);
+ StatisticsRegistry::registerStat(&d_eval_lits_unknown);
}
-ModelEngineBuilder::Statistics::~Statistics(){
+QModelBuilderIG::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_num_quants_init);
StatisticsRegistry::unregisterStat(&d_num_partial_quants_init);
StatisticsRegistry::unregisterStat(&d_init_inst_gen_lemmas);
StatisticsRegistry::unregisterStat(&d_inst_gen_lemmas);
+ StatisticsRegistry::unregisterStat(&d_eval_formulas);
+ StatisticsRegistry::unregisterStat(&d_eval_uf_terms);
+ StatisticsRegistry::unregisterStat(&d_eval_lits);
+ StatisticsRegistry::unregisterStat(&d_eval_lits_unknown);
}
-bool ModelEngineBuilder::isQuantifierActive( Node f ){
- return ( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
+bool QModelBuilderIG::isQuantifierActive( Node f ){
+ return !f.hasAttribute(QRewriteRuleAttribute()) &&
+ ( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
}
-bool ModelEngineBuilder::isTermActive( Node n ){
+bool QModelBuilderIG::isTermActive( Node n ){
return !n.getAttribute(NoMatchAttribute()) || //it is not congruent to another active term
- ( n.getAttribute(ModelBasisArgAttribute())==1 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments
+ ( n.getAttribute(ModelBasisArgAttribute())!=0 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments
//and is not congruent modulo model basis
//to another active term
}
+//do exhaustive instantiation
+bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
+ if( optUseModel() ){
+
+ RepSetIterator riter( d_qe, &(d_qe->getModel()->d_rep_set) );
+ if( riter.setQuantifier( f ) ){
+ FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
+ Debug("inst-fmf-ei") << "Reset evaluate..." << std::endl;
+ fmig->resetEvaluate();
+ Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
+ while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
+ d_triedLemmas++;
+ for( int i=0; i<(int)riter.d_index.size(); i++ ){
+ Trace("try") << i << " : " << riter.d_index[i] << " : " << riter.getTerm( i ) << std::endl;
+ }
+ int eval = 0;
+ int depIndex;
+ //see if instantiation is already true in current model
+ Debug("fmf-model-eval") << "Evaluating ";
+ riter.debugPrintSmall("fmf-model-eval");
+ Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+ //if evaluate(...)==1, then the instantiation is already true in the model
+ // depIndex is the index of the least significant variable that this evaluation relies upon
+ depIndex = riter.getNumTerms()-1;
+ eval = fmig->evaluate( d_qe->getTermDatabase()->getInstConstantBody( f ), depIndex, &riter );
+ if( eval==1 ){
+ Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
+ }else{
+ Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
+ }
+ if( eval==1 ){
+ //instantiation is already true -> skip
+ riter.increment2( depIndex );
+ }else{
+ //instantiation was not shown to be true, construct the match
+ InstMatch m;
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ m.set( d_qe, f, riter.d_index_order[i], riter.getTerm( i ) );
+ }
+ Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
+ //add as instantiation
+ if( d_qe->addInstantiation( f, m ) ){
+ d_addedLemmas++;
+ //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
+ if( eval==-1 ){
+ riter.increment2( depIndex );
+ }else{
+ riter.increment();
+ }
+ }else{
+ Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
+ riter.increment();
+ }
+ }
+ }
+ //print debugging information
+ if( fmig ){
+ d_statistics.d_eval_formulas += fmig->d_eval_formulas;
+ d_statistics.d_eval_uf_terms += fmig->d_eval_uf_terms;
+ d_statistics.d_eval_lits += fmig->d_eval_lits;
+ d_statistics.d_eval_lits_unknown += fmig->d_eval_lits_unknown;
+ }
+ Trace("inst-fmf-ei") << "Finished: " << std::endl;
+ Trace("inst-fmf-ei") << " Inst Tried: " << d_triedLemmas << std::endl;
+ Trace("inst-fmf-ei") << " Inst Added: " << d_addedLemmas << std::endl;
+ if( d_addedLemmas>1000 ){
+ Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
+ Trace("model-engine-warn") << " Inst Tried: " << d_triedLemmas << std::endl;
+ Trace("model-engine-warn") << " Inst Added: " << d_addedLemmas << std::endl;
+ Trace("model-engine-warn") << std::endl;
+ }
+ }
+ //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
+ d_incomplete_check = riter.d_incomplete;
+ return true;
+ }else{
+ return false;
+ }
+}
+
-void ModelEngineBuilderDefault::reset( FirstOrderModel* fm ){
+void QModelBuilderDefault::reset( FirstOrderModel* fm ){
d_quant_selection_lit.clear();
d_quant_selection_lit_candidates.clear();
d_quant_selection_lit_terms.clear();
@@ -369,7 +485,7 @@ void ModelEngineBuilderDefault::reset( FirstOrderModel* fm ){
}
-int ModelEngineBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
+int QModelBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
/*
size_t maxChildren = 0;
for( size_t i=0; i<uf_terms.size(); i++ ){
@@ -383,7 +499,8 @@ int ModelEngineBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms
return 0;
}
-void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+void QModelBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
//the pro/con preferences for this quantifier
std::vector< Node > pro_con[2];
@@ -408,7 +525,7 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f )
// constant definitions.
bool isConst = true;
std::vector< Node > uf_terms;
- if( n.hasAttribute(InstConstantAttribute()) ){
+ if( TermDb::hasInstConstAttr(n) ){
isConst = false;
if( gn.getKind()==APPLY_UF ){
uf_terms.push_back( gn );
@@ -416,9 +533,9 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f )
}else if( gn.getKind()==EQUAL ){
isConst = true;
for( int j=0; j<2; j++ ){
- if( n[j].hasAttribute(InstConstantAttribute()) ){
+ if( TermDb::hasInstConstAttr(n[j]) ){
if( n[j].getKind()==APPLY_UF &&
- fm->d_uf_model_tree.find( gn[j].getOperator() )!=fm->d_uf_model_tree.end() ){
+ fmig->d_uf_model_tree.find( gn[j].getOperator() )!=fmig->d_uf_model_tree.end() ){
uf_terms.push_back( gn[j] );
isConst = isConst && hasConstantDefinition( gn[j] );
}else{
@@ -506,14 +623,14 @@ void ModelEngineBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f )
for( int k=0; k<2; k++ ){
for( int j=0; j<(int)pro_con[k].size(); j++ ){
Node op = pro_con[k][j].getOperator();
- Node r = fm->getRepresentative( pro_con[k][j] );
+ Node r = fmig->getRepresentative( pro_con[k][j] );
d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
}
}
}
}
-int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
+int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
int addedLemmas = 0;
//we wish to add all known exceptions to our selection literal for f. this will help to refine our current model.
//This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
@@ -523,17 +640,16 @@ int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
for( size_t i=0; i<d_quant_selection_lit_candidates[f].size(); i++ ){
bool phase = d_quant_selection_lit_candidates[f][i].getKind()!=NOT;
Node lit = d_quant_selection_lit_candidates[f][i].getKind()==NOT ? d_quant_selection_lit_candidates[f][i][0] : d_quant_selection_lit_candidates[f][i];
- Assert( lit.hasAttribute(InstConstantAttribute()) );
+ Assert( TermDb::hasInstConstAttr(lit) );
std::vector< Node > tr_terms;
if( lit.getKind()==APPLY_UF ){
//only match predicates that are contrary to this one, use literal matching
Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false );
- d_qe->getTermDatabase()->setInstantiationConstantAttr( eq, f );
tr_terms.push_back( eq );
}else if( lit.getKind()==EQUAL ){
//collect trigger terms
for( int j=0; j<2; j++ ){
- if( lit[j].hasAttribute(InstConstantAttribute()) ){
+ if( TermDb::hasInstConstAttr(lit[j]) ){
if( lit[j].getKind()==APPLY_UF ){
tr_terms.push_back( lit[j] );
}else{
@@ -564,7 +680,8 @@ int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
return addedLemmas;
}
-void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
+void QModelBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
if( optReconsiderFuncConstants() ){
//reconsider constant functions that weren't necessary
if( d_uf_model_constructed[op] ){
@@ -573,8 +690,8 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
Node v = d_uf_prefs[op].d_const_val;
if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){
Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl;
- fm->d_uf_model_tree[op].clear();
- fm->d_uf_model_gen[op].clear();
+ fmig->d_uf_model_tree[op].clear();
+ fmig->d_uf_model_gen[op].clear();
d_uf_model_constructed[op] = false;
}
}
@@ -586,20 +703,20 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
Trace("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
//set the values in the model
- for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
- Node n = fm->d_uf_terms[op][i];
+ for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
+ Node n = fmig->d_uf_terms[op][i];
if( isTermActive( n ) ){
- Node v = fm->getRepresentative( n );
- Trace("fmf-model-cons") << "Set term " << n << " : " << fm->d_rep_set.getIndexFor( v ) << " " << v << std::endl;
+ Node v = fmig->getRepresentative( n );
+ Trace("fmf-model-cons") << "Set term " << n << " : " << fmig->d_rep_set.getIndexFor( v ) << " " << v << std::endl;
//if this assertion did not help the model, just consider it ground
//set n = v in the model tree
//set it as ground value
- fm->d_uf_model_gen[op].setValue( fm, n, v );
- if( fm->d_uf_model_gen[op].optUsePartialDefaults() ){
+ fmig->d_uf_model_gen[op].setValue( fm, n, v );
+ if( fmig->d_uf_model_gen[op].optUsePartialDefaults() ){
//also set as default value if necessary
- if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 ){
+ if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())!=0 ){
Trace("fmf-model-cons") << " Set as default." << std::endl;
- fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
if( n==defaultTerm ){
//incidentally already set, we will not need to find a default value
setDefaultVal = false;
@@ -607,7 +724,7 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
}
}else{
if( n==defaultTerm ){
- fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
//incidentally already set, we will not need to find a default value
setDefaultVal = false;
}
@@ -619,12 +736,19 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
Trace("fmf-model-cons") << " Choose default value..." << std::endl;
//chose defaultVal based on heuristic, currently the best ratio of "pro" responses
Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
+ if( defaultVal.isNull() ){
+ if (!fmig->d_rep_set.hasType(defaultTerm.getType())) {
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(defaultTerm.getType());
+ fmig->d_rep_set.d_type_reps[defaultTerm.getType()].push_back(mbt);
+ }
+ defaultVal = fmig->d_rep_set.d_type_reps[defaultTerm.getType()][0];
+ }
Assert( !defaultVal.isNull() );
- Trace("fmf-model-cons") << "Set default term : " << fm->d_rep_set.getIndexFor( defaultVal ) << std::endl;
- fm->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
+ Trace("fmf-model-cons") << "Set default term : " << fmig->d_rep_set.getIndexFor( defaultVal ) << std::endl;
+ fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
}
Debug("fmf-model-cons") << " Making model...";
- fm->d_uf_model_gen[op].makeModel( fm, fm->d_uf_model_tree[op] );
+ fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
d_uf_model_constructed[op] = true;
Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl;
}
@@ -635,7 +759,7 @@ void ModelEngineBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op )
////////////////////// Inst-Gen style Model Builder ///////////
-void ModelEngineBuilderInstGen::reset( FirstOrderModel* fm ){
+void QModelBuilderInstGen::reset( FirstOrderModel* fm ){
//for new inst gen
d_quant_selection_formula.clear();
d_term_selected.clear();
@@ -643,15 +767,15 @@ void ModelEngineBuilderInstGen::reset( FirstOrderModel* fm ){
//d_sub_quant_inst_trie.clear();//*
}
-int ModelEngineBuilderInstGen::initializeQuantifier( Node f, Node fp ){
- int addedLemmas = ModelEngineBuilder::initializeQuantifier( f, fp );
+int QModelBuilderInstGen::initializeQuantifier( Node f, Node fp ){
+ int addedLemmas = QModelBuilderIG::initializeQuantifier( f, fp );
for( size_t i=0; i<d_sub_quants[f].size(); i++ ){
addedLemmas += initializeQuantifier( d_sub_quants[f][i], fp );
}
return addedLemmas;
}
-void ModelEngineBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+void QModelBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f ){
//Node fp = getParentQuantifier( f );//*
//bool quantRedundant = ( f!=fp && d_sub_quant_inst_trie[fp].addInstMatch( d_qe, fp, d_sub_quant_inst[ f ], true ) );
//if( f==fp || d_sub_quant_inst_trie[fp].addInstMatch( d_qe, fp, d_sub_quant_inst[ f ], true ) ){//*
@@ -662,7 +786,6 @@ void ModelEngineBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f )
//if( !s.isNull() ){
// s = Rewriter::rewrite( s );
//}
- d_qe->getTermDatabase()->setInstantiationConstantAttr( s, f );
Trace("sel-form-debug") << "Selection formula " << f << std::endl;
Trace("sel-form-debug") << " " << s << std::endl;
if( !s.isNull() ){
@@ -685,7 +808,7 @@ void ModelEngineBuilderInstGen::analyzeQuantifier( FirstOrderModel* fm, Node f )
}
-int ModelEngineBuilderInstGen::doInstGen( FirstOrderModel* fm, Node f ){
+int QModelBuilderInstGen::doInstGen( FirstOrderModel* fm, Node f ){
int addedLemmas = 0;
if( d_quant_sat.find( f )==d_quant_sat.end() ){
Node fp = d_sub_quant_parent.find( f )==d_sub_quant_parent.end() ? f : d_sub_quant_parent[f];
@@ -802,7 +925,7 @@ Node mkAndSelectionFormula( Node n1, Node n2 ){
//if possible, returns a formula n' such that n' => ( n <=> polarity ), and n' is true in the current context,
// and NULL otherwise
-Node ModelEngineBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polarity, int useOption ){
+Node QModelBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polarity, int useOption ){
Trace("sel-form-debug") << "Looking for selection formula " << n << " " << polarity << std::endl;
Node ret;
if( n.getKind()==NOT ){
@@ -911,7 +1034,7 @@ Node ModelEngineBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polar
return ret;
}
-int ModelEngineBuilderInstGen::getSelectionFormulaScore( Node fn ){
+int QModelBuilderInstGen::getSelectionFormulaScore( Node fn ){
if( fn.getType().isBoolean() ){
if( fn.getKind()==APPLY_UF ){
Node op = fn.getOperator();
@@ -929,13 +1052,13 @@ int ModelEngineBuilderInstGen::getSelectionFormulaScore( Node fn ){
}
}
-void ModelEngineBuilderInstGen::setSelectedTerms( Node s ){
+void QModelBuilderInstGen::setSelectedTerms( Node s ){
//if it is apply uf and has model basis arguments, then mark term as being "selected"
if( s.getKind()==APPLY_UF ){
Assert( s.hasAttribute(ModelBasisArgAttribute()) );
if( !s.hasAttribute(ModelBasisArgAttribute()) ) std::cout << "no mba!! " << s << std::endl;
- if( s.getAttribute(ModelBasisArgAttribute())==1 ){
+ if( s.getAttribute(ModelBasisArgAttribute())!=0 ){
d_term_selected[ s ] = true;
Trace("sel-form-term") << " " << s << " is a selected term." << std::endl;
}
@@ -945,7 +1068,7 @@ void ModelEngineBuilderInstGen::setSelectedTerms( Node s ){
}
}
-bool ModelEngineBuilderInstGen::isUsableSelectionLiteral( Node n, int useOption ){
+bool QModelBuilderInstGen::isUsableSelectionLiteral( Node n, int useOption ){
if( n.getKind()==FORALL ){
return false;
}else if( n.getKind()!=APPLY_UF ){
@@ -964,7 +1087,7 @@ bool ModelEngineBuilderInstGen::isUsableSelectionLiteral( Node n, int useOption
return true;
}
-void ModelEngineBuilderInstGen::getParentQuantifierMatch( InstMatch& mp, Node fp, InstMatch& m, Node f ){
+void QModelBuilderInstGen::getParentQuantifierMatch( InstMatch& mp, Node fp, InstMatch& m, Node f ){
if( f!=fp ){
//std::cout << "gpqm " << fp << " " << f << " " << m << std::endl;
//std::cout << " " << fp[0].getNumChildren() << " " << f[0].getNumChildren() << std::endl;
@@ -988,20 +1111,21 @@ void ModelEngineBuilderInstGen::getParentQuantifierMatch( InstMatch& mp, Node fp
}
}
-void ModelEngineBuilderInstGen::constructModelUf( FirstOrderModel* fm, Node op ){
+void QModelBuilderInstGen::constructModelUf( FirstOrderModel* fm, Node op ){
+ FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
bool setDefaultVal = true;
Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
//set the values in the model
- for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
- Node n = fm->d_uf_terms[op][i];
+ for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){
+ Node n = fmig->d_uf_terms[op][i];
if( isTermActive( n ) ){
- Node v = fm->getRepresentative( n );
- fm->d_uf_model_gen[op].setValue( fm, n, v );
+ Node v = fmig->getRepresentative( n );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v );
}
//also possible set as default
if( d_term_selected.find( n )!=d_term_selected.end() || n==defaultTerm ){
- Node v = fm->getRepresentative( n );
- fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ Node v = fmig->getRepresentative( n );
+ fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
if( n==defaultTerm ){
setDefaultVal = false;
}
@@ -1010,12 +1134,12 @@ void ModelEngineBuilderInstGen::constructModelUf( FirstOrderModel* fm, Node op )
//set the overall default value if not set already (is this necessary??)
if( setDefaultVal ){
Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
- fm->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
+ fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
}
- fm->d_uf_model_gen[op].makeModel( fm, fm->d_uf_model_tree[op] );
+ fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
d_uf_model_constructed[op] = true;
}
-bool ModelEngineBuilderInstGen::existsInstantiation( Node f, InstMatch& m, bool modEq, bool modInst ){
+bool QModelBuilderInstGen::existsInstantiation( Node f, InstMatch& m, bool modEq, bool modInst ){
return d_child_sub_quant_inst_trie[f].existsInstMatch( d_qe, f, m, modEq, true );
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h
index 31448acee..b96c58767 100644
--- a/src/theory/quantifiers/model_builder.h
+++ b/src/theory/quantifiers/model_builder.h
@@ -25,6 +25,42 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
+
+class QModelBuilder : public TheoryEngineModelBuilder
+{
+protected:
+ //the model we are working with
+ context::CDO< FirstOrderModel* > d_curr_model;
+ //quantifiers engine
+ QuantifiersEngine* d_qe;
+public:
+ QModelBuilder( context::Context* c, QuantifiersEngine* qe );
+ virtual ~QModelBuilder(){}
+ // is quantifier active?
+ virtual bool isQuantifierActive( Node f );
+ //do exhaustive instantiation
+ virtual bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; }
+ //whether to construct model
+ virtual bool optUseModel();
+ //whether to construct model at fullModel = true
+ virtual bool optBuildAtFullModel() { return false; }
+ //consider axioms
+ bool d_considerAxioms;
+ /** number of lemmas generated while building model */
+ //is the exhaustive instantiation incomplete?
+ bool d_incomplete_check;
+ int d_addedLemmas;
+ int d_triedLemmas;
+ /** exist instantiation ? */
+ virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
+ //debug model
+ void debugModel( FirstOrderModel* fm );
+};
+
+
+
+
+
/** Attribute true for nodes that should not be used when considered for inst-gen basis */
struct BasisNoMatchAttributeId {};
/** use the special for boolean flag */
@@ -47,17 +83,13 @@ public:
/** model builder class
* This class is capable of building candidate models based on the current quantified formulas
* that are asserted. Use:
- * (1) call ModelEngineBuilder::buildModel( m, false );, where m is a FirstOrderModel
+ * (1) call QModelBuilder::buildModel( m, false );, where m is a FirstOrderModel
* (2) if candidate model is determined to be a real model,
- then call ModelEngineBuilder::buildModel( m, true );
+ then call QModelBuilder::buildModel( m, true );
*/
-class ModelEngineBuilder : public TheoryEngineModelBuilder
+class QModelBuilderIG : public QModelBuilder
{
protected:
- //quantifiers engine
- QuantifiersEngine* d_qe;
- //the model we are working with
- context::CDO< FirstOrderModel* > d_curr_model;
//map from operators to model preference data
std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
//built model uf
@@ -66,6 +98,8 @@ protected:
bool d_didInstGen;
/** process build model */
virtual void processBuildModel( TheoryModel* m, bool fullModel );
+ /** get current model value */
+ Node getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial );
protected:
//reset
virtual void reset( FirstOrderModel* fm ) = 0;
@@ -90,25 +124,13 @@ protected: //helper functions
/** term has constant definition */
bool hasConstantDefinition( Node n );
public:
- ModelEngineBuilder( context::Context* c, QuantifiersEngine* qe );
- virtual ~ModelEngineBuilder(){}
- /** number of lemmas generated while building model */
- int d_addedLemmas;
- //consider axioms
- bool d_considerAxioms;
- // set effort
- void setEffort( int effort );
- //debug model
- void debugModel( FirstOrderModel* fm );
+ QModelBuilderIG( context::Context* c, QuantifiersEngine* qe );
+ virtual ~QModelBuilderIG(){}
public:
- //whether to construct model
- virtual bool optUseModel();
//whether to add inst-gen lemmas
virtual bool optInstGen();
//whether to only consider only quantifier per round of inst-gen
virtual bool optOneQuantPerRoundInstGen();
- //whether we should exhaustively instantiate quantifiers where inst-gen is not working
- virtual bool optExhInstNonInstGenQuant();
/** statistics class */
class Statistics {
public:
@@ -116,22 +138,26 @@ public:
IntStat d_num_partial_quants_init;
IntStat d_init_inst_gen_lemmas;
IntStat d_inst_gen_lemmas;
+ IntStat d_eval_formulas;
+ IntStat d_eval_uf_terms;
+ IntStat d_eval_lits;
+ IntStat d_eval_lits_unknown;
Statistics();
~Statistics();
};
Statistics d_statistics;
- // is quantifier active?
- bool isQuantifierActive( Node f );
// is term active
bool isTermActive( Node n );
// is term selected
virtual bool isTermSelected( Node n ) { return false; }
- /** exist instantiation ? */
- virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
/** quantifier has inst-gen definition */
virtual bool hasInstGen( Node f ) = 0;
/** did inst gen this round? */
bool didInstGen() { return d_didInstGen; }
+ // is quantifier active?
+ bool isQuantifierActive( Node f );
+ //do exhaustive instantiation
+ bool doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
//temporary stats
int d_numQuantSat;
@@ -140,10 +166,10 @@ public:
int d_numQuantNoSelForm;
//temporary stat
int d_instGenMatches;
-};/* class ModelEngineBuilder */
+};/* class QModelBuilder */
-class ModelEngineBuilderDefault : public ModelEngineBuilder
+class QModelBuilderDefault : public QModelBuilderIG
{
private: ///information for (old) InstGen
//map from quantifiers to their selection literals
@@ -167,15 +193,15 @@ protected:
//theory-specific build models
void constructModelUf( FirstOrderModel* fm, Node op );
public:
- ModelEngineBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : ModelEngineBuilder( c, qe ){}
- ~ModelEngineBuilderDefault(){}
+ QModelBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
+ ~QModelBuilderDefault(){}
//options
bool optReconsiderFuncConstants() { return true; }
//has inst gen
bool hasInstGen( Node f ) { return !d_quant_selection_lit[f].isNull(); }
};
-class ModelEngineBuilderInstGen : public ModelEngineBuilder
+class QModelBuilderInstGen : public QModelBuilderIG
{
private: ///information for (new) InstGen
//map from quantifiers to their selection formulas
@@ -217,8 +243,8 @@ private:
//get parent quantifier
Node getParentQuantifier( Node f ) { return d_sub_quant_parent.find( f )==d_sub_quant_parent.end() ? f : d_sub_quant_parent[f]; }
public:
- ModelEngineBuilderInstGen( context::Context* c, QuantifiersEngine* qe ) : ModelEngineBuilder( c, qe ){}
- ~ModelEngineBuilderInstGen(){}
+ QModelBuilderInstGen( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
+ ~QModelBuilderInstGen(){}
// is term selected
bool isTermSelected( Node n ) { return d_term_selected.find( n )!=d_term_selected.end(); }
/** exist instantiation ? */
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index a69b278c0..cb8cb8154 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -18,13 +18,10 @@
#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_strong_solver.h"
#include "theory/quantifiers/options.h"
-#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/quantifiers_attributes.h"
-#define EVAL_FAIL_SKIP_MULTIPLE
-
using namespace std;
using namespace CVC4;
using namespace CVC4::kind;
@@ -35,15 +32,21 @@ using namespace CVC4::theory::inst;
//Model Engine constructor
ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
-QuantifiersModule( qe ),
-d_rel_domain( qe, qe->getModel() ){
+QuantifiersModule( qe ){
- if( options::fmfNewInstGen() ){
- d_builder = new ModelEngineBuilderInstGen( c, qe );
+ if( options::fmfFullModelCheck() ){
+ d_builder = new fmcheck::FullModelChecker( c, qe );
+ }else if( options::fmfNewInstGen() ){
+ d_builder = new QModelBuilderInstGen( c, qe );
}else{
- d_builder = new ModelEngineBuilderDefault( c, qe );
+ d_builder = new QModelBuilderDefault( c, qe );
}
+ if( options::fmfRelevantDomain() ){
+ d_rel_dom = new RelevantDomain( qe, qe->getModel() );
+ }else{
+ d_rel_dom = NULL;
+ }
}
void ModelEngine::check( Theory::Effort e ){
@@ -57,6 +60,7 @@ void ModelEngine::check( Theory::Effort e ){
clSet = double(clock())/double(CLOCKS_PER_SEC);
}
++(d_statistics.d_inst_rounds);
+ bool buildAtFullModel = d_builder->optBuildAtFullModel();
//two effort levels: first try exhaustive instantiation without axioms, then with.
int startEffort = ( !fm->isAxiomAsserted() || options::axiomInstMode()==AXIOM_INST_MODE_DEFAULT ) ? 1 : 0;
for( int effort=startEffort; effort<2; effort++ ){
@@ -66,8 +70,9 @@ void ModelEngine::check( Theory::Effort e ){
Trace("model-engine") << "---Model Engine Round---" << std::endl;
//initialize the model
Trace("model-engine-debug") << "Build model..." << std::endl;
- d_builder->setEffort( effort );
- d_builder->buildModel( fm, false );
+ d_builder->d_considerAxioms = effort>=1;
+ d_builder->d_addedLemmas = 0;
+ d_builder->buildModel( fm, buildAtFullModel );
addedLemmas += (int)d_builder->d_addedLemmas;
//if builder has lemmas, add and return
if( addedLemmas==0 ){
@@ -81,11 +86,7 @@ void ModelEngine::check( Theory::Effort e ){
Debug("fmf-model-complete") << std::endl;
debugPrint("fmf-model-complete");
//successfully built an acceptable model, now check it
- addedLemmas += checkModel( check_model_full );
- }else if( d_builder->didInstGen() && d_builder->optExhInstNonInstGenQuant() ){
- Trace("model-engine-debug") << "Check model for non-inst gen quantifiers..." << std::endl;
- //check quantifiers that inst-gen didn't apply to
- addedLemmas += checkModel( check_model_no_inst_gen );
+ addedLemmas += checkModel();
}
}
if( addedLemmas==0 ){
@@ -108,7 +109,7 @@ void ModelEngine::check( Theory::Effort e ){
//CVC4 will answer SAT or unknown
Trace("fmf-consistent") << std::endl;
debugPrint("fmf-consistent");
- if( options::produceModels() ){
+ if( options::produceModels() && !buildAtFullModel ){
// finish building the model
d_builder->buildModel( fm, true );
}
@@ -131,28 +132,12 @@ void ModelEngine::assertNode( Node f ){
}
-bool ModelEngine::optOneInstPerQuantRound(){
- return options::fmfOneInstPerRound();
-}
-
-bool ModelEngine::optUseRelevantDomain(){
- return options::fmfRelevantDomain();
-}
-
bool ModelEngine::optOneQuantPerRound(){
return options::fmfOneQuantPerRound();
}
-bool ModelEngine::optExhInstEvalSkipMultiple(){
-#ifdef EVAL_FAIL_SKIP_MULTIPLE
- return true;
-#else
- return false;
-#endif
-}
-int ModelEngine::checkModel( int checkOption ){
- int addedLemmas = 0;
+int ModelEngine::checkModel(){
FirstOrderModel* fm = d_quantEngine->getModel();
//for debugging
if( Trace.isOn("model-engine") || Trace.isOn("model-engine-debug") ){
@@ -161,27 +146,28 @@ int ModelEngine::checkModel( int checkOption ){
if( it->first.isSort() ){
Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
Trace("model-engine-debug") << " ";
+ Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
for( size_t i=0; i<it->second.size(); i++ ){
//Trace("model-engine-debug") << it->second[i] << " ";
Node r = ((EqualityQueryQuantifiersEngine*)d_quantEngine->getEqualityQuery())->getRepresentative( it->second[i] );
Trace("model-engine-debug") << r << " ";
}
Trace("model-engine-debug") << std::endl;
+ Trace("model-engine-debug") << " Model basis term : " << mbt << std::endl;
}
}
}
- //compute the relevant domain if necessary
- if( optUseRelevantDomain() ){
- d_rel_domain.compute();
+ //relevant domain?
+ if( d_rel_dom ){
+ d_rel_dom->compute();
}
+
d_triedLemmas = 0;
- d_testLemmas = 0;
- d_relevantLemmas = 0;
+ d_addedLemmas = 0;
d_totalLemmas = 0;
- Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
+ //for statistics
for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
Node f = fm->getAssertedQuantifier( i );
- //keep track of total instantiations for statistics
int totalInst = 1;
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
TypeNode tn = f[0][i].getType();
@@ -190,133 +176,85 @@ int ModelEngine::checkModel( int checkOption ){
}
}
d_totalLemmas += totalInst;
- //determine if we should check this quantifiers
- bool checkQuant = false;
- if( checkOption==check_model_full ){
- checkQuant = d_builder->isQuantifierActive( f );
- }else if( checkOption==check_model_no_inst_gen ){
- checkQuant = !d_builder->hasInstGen( f );
- }
- //if we need to consider this quantifier on this iteration
- if( checkQuant ){
- addedLemmas += exhaustiveInstantiate( f, optUseRelevantDomain() );
- if( Trace.isOn("model-engine-warn") ){
- if( addedLemmas>10000 ){
- Debug("fmf-exit") << std::endl;
- debugPrint("fmf-exit");
- exit( 0 );
+ }
+
+ Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
+ int e_max = options::fmfFullModelCheck() && options::fmfModelBasedInst() ? 2 : 1;
+ for( int e=0; e<e_max; e++) {
+ if (d_addedLemmas==0) {
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ //determine if we should check this quantifier
+ if( d_builder->isQuantifierActive( f ) ){
+ exhaustiveInstantiate( f, e );
+ if( Trace.isOn("model-engine-warn") ){
+ if( d_addedLemmas>10000 ){
+ Debug("fmf-exit") << std::endl;
+ debugPrint("fmf-exit");
+ exit( 0 );
+ }
+ }
+ if( optOneQuantPerRound() && d_addedLemmas>0 ){
+ break;
+ }
}
}
- if( optOneQuantPerRound() && addedLemmas>0 ){
- break;
- }
}
}
//print debug information
if( Trace.isOn("model-engine") ){
Trace("model-engine") << "Instantiate axioms : " << ( d_builder->d_considerAxioms ? "yes" : "no" ) << std::endl;
- Trace("model-engine") << "Added Lemmas = " << addedLemmas << " / " << d_triedLemmas << " / ";
- Trace("model-engine") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl;
+ Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / ";
+ Trace("model-engine") << d_totalLemmas << std::endl;
}
- d_statistics.d_exh_inst_lemmas += addedLemmas;
- return addedLemmas;
+ d_statistics.d_exh_inst_lemmas += d_addedLemmas;
+ return d_addedLemmas;
}
-int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){
- int addedLemmas = 0;
- Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << "..." << std::endl;
- Debug("inst-fmf-ei") << " Instantiation Constants: ";
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
- }
- Debug("inst-fmf-ei") << std::endl;
-
- //create a rep set iterator and iterate over the (relevant) domain of the quantifier
- RepSetIterator riter( &(d_quantEngine->getModel()->d_rep_set) );
- if( riter.setQuantifier( f ) ){
- //set the domain for the iterator (the sufficient set of instantiations to try)
- if( useRelInstDomain ){
- riter.setDomain( d_rel_domain.d_quant_inst_domain[f] );
+void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
+ //first check if the builder can do the exhaustive instantiation
+ d_builder->d_triedLemmas = 0;
+ d_builder->d_addedLemmas = 0;
+ d_builder->d_incomplete_check = false;
+ if( d_builder->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ) ){
+ d_triedLemmas += d_builder->d_triedLemmas;
+ d_addedLemmas += d_builder->d_addedLemmas;
+ d_incomplete_check = d_incomplete_check || d_builder->d_incomplete_check;
+ }else{
+ Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
+ Debug("inst-fmf-ei") << " Instantiation Constants: ";
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
}
- d_quantEngine->getModel()->resetEvaluate();
- int tests = 0;
- int triedLemmas = 0;
- while( !riter.isFinished() && ( addedLemmas==0 || !optOneInstPerQuantRound() ) ){
- d_testLemmas++;
- int eval = 0;
- int depIndex;
- if( d_builder->optUseModel() ){
- //see if instantiation is already true in current model
- Debug("fmf-model-eval") << "Evaluating ";
- riter.debugPrintSmall("fmf-model-eval");
- Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
- tests++;
- //if evaluate(...)==1, then the instantiation is already true in the model
- // depIndex is the index of the least significant variable that this evaluation relies upon
- depIndex = riter.getNumTerms()-1;
- eval = d_quantEngine->getModel()->evaluate( d_quantEngine->getTermDatabase()->getInstConstantBody( f ), depIndex, &riter );
- if( eval==1 ){
- Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
- }else{
- Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
- }
- }
- if( eval==1 ){
- //instantiation is already true -> skip
- riter.increment2( depIndex );
- }else{
+ Debug("inst-fmf-ei") << std::endl;
+ //create a rep set iterator and iterate over the (relevant) domain of the quantifier
+ RepSetIterator riter( d_quantEngine, &(d_quantEngine->getModel()->d_rep_set) );
+ if( riter.setQuantifier( f ) ){
+ Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
+ int triedLemmas = 0;
+ int addedLemmas = 0;
+ while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
//instantiation was not shown to be true, construct the match
InstMatch m;
for( int i=0; i<riter.getNumTerms(); i++ ){
- m.set( d_quantEngine->getTermDatabase()->getInstantiationConstant( f, riter.d_index_order[i] ), riter.getTerm( i ) );
+ m.set( d_quantEngine, f, riter.d_index_order[i], riter.getTerm( i ) );
}
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
triedLemmas++;
- d_triedLemmas++;
//add as instantiation
if( d_quantEngine->addInstantiation( f, m ) ){
addedLemmas++;
- //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
- if( eval==-1 && optExhInstEvalSkipMultiple() ){
- riter.increment2( depIndex );
- }else{
- riter.increment();
- }
}else{
Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
- riter.increment();
}
+ riter.increment();
}
+ d_addedLemmas += addedLemmas;
+ d_triedLemmas += triedLemmas;
}
- //print debugging information
- d_statistics.d_eval_formulas += d_quantEngine->getModel()->d_eval_formulas;
- d_statistics.d_eval_uf_terms += d_quantEngine->getModel()->d_eval_uf_terms;
- d_statistics.d_eval_lits += d_quantEngine->getModel()->d_eval_lits;
- d_statistics.d_eval_lits_unknown += d_quantEngine->getModel()->d_eval_lits_unknown;
- int relevantInst = 1;
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- relevantInst = relevantInst * (int)riter.d_domain[i].size();
- }
- d_relevantLemmas += relevantInst;
- Trace("inst-fmf-ei") << "Finished: " << std::endl;
- //Debug("inst-fmf-ei") << " Inst Total: " << totalInst << std::endl;
- Trace("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl;
- Trace("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl;
- Trace("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl;
- Trace("inst-fmf-ei") << " # Tests: " << tests << std::endl;
- if( addedLemmas>1000 ){
- Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
- //Trace("model-engine-warn") << " Inst Total: " << totalInst << std::endl;
- Trace("model-engine-warn") << " Inst Relevant: " << relevantInst << std::endl;
- Trace("model-engine-warn") << " Inst Tried: " << triedLemmas << std::endl;
- Trace("model-engine-warn") << " Inst Added: " << addedLemmas << std::endl;
- Trace("model-engine-warn") << " # Tests: " << tests << std::endl;
- Trace("model-engine-warn") << std::endl;
- }
+ //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
+ d_incomplete_check = d_incomplete_check || riter.d_incomplete;
}
- //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
- d_incomplete_check = d_incomplete_check || riter.d_incomplete;
- return addedLemmas;
}
void ModelEngine::debugPrint( const char* c ){
@@ -336,26 +274,14 @@ void ModelEngine::debugPrint( const char* c ){
ModelEngine::Statistics::Statistics():
d_inst_rounds("ModelEngine::Inst_Rounds", 0),
- d_eval_formulas("ModelEngine::Eval_Formulas", 0 ),
- d_eval_uf_terms("ModelEngine::Eval_Uf_Terms", 0 ),
- d_eval_lits("ModelEngine::Eval_Lits", 0 ),
- d_eval_lits_unknown("ModelEngine::Eval_Lits_Unknown", 0 ),
d_exh_inst_lemmas("ModelEngine::Exhaustive_Instantiation_Lemmas", 0 )
{
StatisticsRegistry::registerStat(&d_inst_rounds);
- StatisticsRegistry::registerStat(&d_eval_formulas);
- StatisticsRegistry::registerStat(&d_eval_uf_terms);
- StatisticsRegistry::registerStat(&d_eval_lits);
- StatisticsRegistry::registerStat(&d_eval_lits_unknown);
StatisticsRegistry::registerStat(&d_exh_inst_lemmas);
}
ModelEngine::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_inst_rounds);
- StatisticsRegistry::unregisterStat(&d_eval_formulas);
- StatisticsRegistry::unregisterStat(&d_eval_uf_terms);
- StatisticsRegistry::unregisterStat(&d_eval_lits);
- StatisticsRegistry::unregisterStat(&d_eval_lits_unknown);
StatisticsRegistry::unregisterStat(&d_exh_inst_lemmas);
}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index 386864164..1c2c38c51 100644
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
@@ -20,6 +20,7 @@
#include "theory/quantifiers_engine.h"
#include "theory/quantifiers/model_builder.h"
#include "theory/model.h"
+#include "theory/quantifiers/full_model_check.h"
#include "theory/quantifiers/relevant_domain.h"
namespace CVC4 {
@@ -31,38 +32,31 @@ class ModelEngine : public QuantifiersModule
friend class RepSetIterator;
private:
/** builder class */
- ModelEngineBuilder* d_builder;
+ QModelBuilder* d_builder;
private: //analysis of current model:
- //relevant domain
- RelevantDomain d_rel_domain;
- //is the exhaustive instantiation incomplete?
- bool d_incomplete_check;
+ RelevantDomain* d_rel_dom;
private:
//options
- bool optOneInstPerQuantRound();
- bool optUseRelevantDomain();
bool optOneQuantPerRound();
- bool optExhInstEvalSkipMultiple();
private:
- enum{
- check_model_full,
- check_model_no_inst_gen,
- };
//check model
- int checkModel( int checkOption );
- //exhaustively instantiate quantifier (possibly using mbqi), return number of lemmas produced
- int exhaustiveInstantiate( Node f, bool useRelInstDomain = false );
+ int checkModel();
+ //exhaustively instantiate quantifier (possibly using mbqi)
+ void exhaustiveInstantiate( Node f, int effort = 0 );
private:
//temporary statistics
+ //is the exhaustive instantiation incomplete?
+ bool d_incomplete_check;
+ int d_addedLemmas;
int d_triedLemmas;
- int d_testLemmas;
int d_totalLemmas;
- int d_relevantLemmas;
public:
ModelEngine( context::Context* c, QuantifiersEngine* qe );
~ModelEngine(){}
+ //get relevant domain
+ RelevantDomain * getRelevantDomain() { return d_rel_dom; }
//get the builder
- ModelEngineBuilder* getModelBuilder() { return d_builder; }
+ QModelBuilder* getModelBuilder() { return d_builder; }
public:
void check( Theory::Effort e );
void registerQuantifier( Node f );
@@ -74,10 +68,6 @@ public:
class Statistics {
public:
IntStat d_inst_rounds;
- IntStat d_eval_formulas;
- IntStat d_eval_uf_terms;
- IntStat d_eval_lits;
- IntStat d_eval_lits_unknown;
IntStat d_exh_inst_lemmas;
Statistics();
~Statistics();
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 60f5a171d..57211ade7 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -24,8 +24,11 @@ option prenexQuant /--disable-prenex-quant bool :default true
# Whether to variable-eliminate quantifiers.
# For example, forall x y. ( P( x, y ) V x != c ) will be rewritten to
# forall y. P( c, y )
-option varElimQuant --var-elim-quant bool :default false
- enable variable elimination of quantified formulas
+option varElimQuant /--disable-var-elim-quant bool :default true
+ disable simple variable elimination for quantified formulas
+
+option simpleIteLiftQuant /--disable-ite-lift-quant bool :default true
+ disable simple ite lifting for quantified formulas
# Whether to CNF quantifier bodies
option cnfQuant --cnf-quant bool :default false
@@ -47,6 +50,9 @@ option aggressiveMiniscopeQuant --ag-miniscope-quant bool :default false
# Whether to perform quantifier macro expansion
option macrosQuant --macros-quant bool :default false
perform quantifiers macro expansions
+# Whether to perform first-order propagation
+option foPropQuant --fo-prop-quant bool :default false
+ perform first-order propagation on quantifiers
# Whether to use smart triggers
option smartTriggers /--disable-smart-triggers bool :default true
@@ -54,6 +60,8 @@ option smartTriggers /--disable-smart-triggers bool :default true
# Whether to use relevent triggers
option relevantTriggers /--disable-relevant-triggers bool :default true
prefer triggers that are more relevant based on SInE style analysis
+option relationalTriggers --relational-triggers bool :default false
+ choose relational triggers such as x = f(y), x >= f(y)
# Whether to consider terms in the bodies of quantifiers for matching
option registerQuantBodyTerms --register-quant-body-terms bool :default false
@@ -72,6 +80,8 @@ option cbqi --enable-cbqi/--disable-cbqi bool :default false
turns on counterexample-based quantifier instantiation [off by default]
/turns off counterexample-based quantifier instantiation
+option recurseCbqi --cbqi-recurse bool :default false
+ turns on recursive counterexample-based quantifier instantiation
option userPatternsQuant /--ignore-user-patterns bool :default true
ignore user-provided patterns for quantifier instantiation
@@ -88,6 +98,15 @@ option finiteModelFind --finite-model-find bool :default false
option fmfModelBasedInst /--disable-fmf-mbqi bool :default true
disable model-based quantifier instantiation for finite model finding
+option fmfFullModelCheck --fmf-fmc bool :default false
+ enable full model check for finite model finding
+option fmfFmcSimple /--disable-fmf-fmc-simple bool :default true
+ disable simple models in full model check for finite model finding
+option fmfFmcCoverSimplify /--disable-fmf-fmc-cover-simplify bool :default true
+ disable covering simplification of fmc models
+option fmfFmcInterval --fmf-fmc-interval bool :default false
+ construct interval models for fmc models
+
option fmfOneInstPerRound --fmf-one-inst-per-round bool :default false
only add one instantiation per quantifier per round for fmf
option fmfOneQuantPerRound --fmf-one-quant-per-round bool :default false
@@ -98,13 +117,17 @@ option fmfRelevantDomain --fmf-relevant-domain bool :default false
use relevant domain computation, similar to complete instantiation (Ge, deMoura 09)
option fmfNewInstGen --fmf-new-inst-gen bool :default false
use new inst gen technique for answering sat without exhaustive instantiation
-option fmfInstGen /--disable-fmf-inst-gen bool :default true
- disable Inst-Gen instantiation techniques for finite model finding
+option fmfInstGen --fmf-inst-gen/--disable-fmf-inst-gen bool :read-write :default true
+ enable Inst-Gen instantiation techniques for finite model finding (default)
+/disable Inst-Gen instantiation techniques for finite model finding
option fmfInstGenOneQuantPerRound --fmf-inst-gen-one-quant-per-round bool :default false
only perform Inst-Gen instantiation techniques on one quantifier per round
option fmfFreshDistConst --fmf-fresh-dc bool :default false
use fresh distinguished representative when applying Inst-Gen techniques
+option fmfBoundInt --fmf-bound-int bool :default false
+ finite model finding on bounded integer quantification
+
option axiomInstMode --axiom-inst=MODE CVC4::theory::quantifiers::AxiomInstMode :default CVC4::theory::quantifiers::AXIOM_INST_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToAxiomInstMode :handler-include "theory/quantifiers/options_handlers.h"
policy for instantiating axioms
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index 36db56d0d..59995a510 100644
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -22,6 +22,102 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
+
+bool QuantArith::getMonomial( Node n, std::map< Node, Node >& msum ) {
+ if ( n.getKind()==MULT ){
+ if( n.getNumChildren()==2 && msum.find(n[1])==msum.end() && n[0].isConst() ){
+ msum[n[1]] = n[0];
+ return true;
+ }
+ }else{
+ if( msum.find(n)==msum.end() ){
+ msum[n] = Node::null();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QuantArith::getMonomialSum( Node n, std::map< Node, Node >& msum ) {
+ if ( n.getKind()==PLUS ){
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ if (!getMonomial( n[i], msum )){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return getMonomial( n, msum );
+ }
+}
+
+bool QuantArith::getMonomialSumLit( Node lit, std::map< Node, Node >& msum ) {
+ if( lit.getKind()==GEQ || lit.getKind()==EQUAL ){
+ if( getMonomialSum( lit[0], msum ) ){
+ if( lit[1].isConst() ){
+ if( !lit[1].getConst<Rational>().isZero() ){
+ msum[Node::null()] = negate( lit[1] );
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k ) {
+ if( msum.find(v)!=msum.end() ){
+ std::vector< Node > children;
+ Rational r = msum[v].isNull() ? Rational(1) : msum[v].getConst<Rational>();
+ if ( r.sgn()!=0 ){
+ for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+ if( it->first.isNull() || it->first!=v ){
+ Node m;
+ if( !it->first.isNull() ){
+ if ( !it->second.isNull() ){
+ m = NodeManager::currentNM()->mkNode( MULT, it->second, it->first );
+ }else{
+ m = it->first;
+ }
+ }else{
+ m = it->second;
+ }
+ children.push_back(m);
+ }
+ }
+ veq = children.size()>1 ? NodeManager::currentNM()->mkNode( PLUS, children ) :
+ (children.size()==1 ? children[0] : NodeManager::currentNM()->mkConst( Rational(0) ));
+ if( !r.isNegativeOne() ){
+ if( r.isOne() ){
+ veq = negate(veq);
+ }else{
+ //TODO
+ return false;
+ }
+ }
+ veq = Rewriter::rewrite( veq );
+ veq = NodeManager::currentNM()->mkNode( k, r.sgn()==1 ? v : veq, r.sgn()==1 ? veq : v );
+ return true;
+ }
+ return false;
+ }else{
+ return false;
+ }
+}
+
+Node QuantArith::negate( Node t ) {
+ Node tt = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) ), t );
+ tt = Rewriter::rewrite( tt );
+ return tt;
+}
+
+Node QuantArith::offset( Node t, int i ) {
+ Node tt = NodeManager::currentNM()->mkNode( PLUS, NodeManager::currentNM()->mkConst( Rational(i) ), t );
+ tt = Rewriter::rewrite( tt );
+ return tt;
+}
+
+
void QuantRelevance::registerQuantifier( Node f ){
//compute symbols in f
std::vector< Node > syms;
@@ -93,13 +189,13 @@ QuantPhaseReq::QuantPhaseReq( Node n, bool computeEq ){
for( std::map< Node, bool >::iterator it = d_phase_reqs.begin(); it != d_phase_reqs.end(); ++it ){
Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl;
if( it->first.getKind()==EQUAL ){
- if( it->first[0].hasAttribute(InstConstantAttribute()) ){
- if( !it->first[1].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(it->first[0]) ){
+ if( !quantifiers::TermDb::hasInstConstAttr(it->first[1]) ){
d_phase_reqs_equality_term[ it->first[0] ] = it->first[1];
d_phase_reqs_equality[ it->first[0] ] = it->second;
Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl;
}
- }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){
+ }else if( quantifiers::TermDb::hasInstConstAttr(it->first[1]) ){
d_phase_reqs_equality_term[ it->first[1] ] = it->first[0];
d_phase_reqs_equality[ it->first[1] ] = it->second;
Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl;
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index 6a5726cc7..86c7bc3a0 100644
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
@@ -28,6 +28,18 @@ namespace CVC4 {
namespace theory {
+class QuantArith
+{
+public:
+ static bool getMonomial( Node n, std::map< Node, Node >& msum );
+ static bool getMonomialSum( Node n, std::map< Node, Node >& msum );
+ static bool getMonomialSumLit( Node lit, std::map< Node, Node >& msum );
+ static bool isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k );
+ static Node negate( Node t );
+ static Node offset( Node t, int i );
+};
+
+
class QuantRelevance
{
private:
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index 5bdce5fac..909c9c388 100644
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
@@ -32,6 +32,10 @@ void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){
Trace("quant-attr") << "Set conjecture " << n << std::endl;
ConjectureAttribute ca;
n.setAttribute( ca, true );
+ }else if( attr=="rr_priority" ){
+ //Trace("quant-attr") << "Set rr priority " << n << std::endl;
+ //RrPriorityAttribute rra;
+
}
}else{
for( size_t i=0; i<n.getNumChildren(); i++ ){
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index 878d3ac50..1aebbfcc5 100644
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
@@ -34,6 +34,10 @@ typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute;
struct ConjectureAttributeId {};
typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute;
+/** Attribute priority for rewrite rules */
+//struct RrPriorityAttributeId {};
+//typedef expr::Attribute< RrPriorityAttributeId, uint64_t > RrPriorityAttribute;
+
struct QuantifiersAttributes
{
/** set user attribute
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 5c71f6e6f..e27897a96 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -211,10 +211,6 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
if( in.hasAttribute(NestedQuantAttribute()) ){
setNestedQuantifiers( ret, in.getAttribute(NestedQuantAttribute()) );
}
- if( in.hasAttribute(InstConstantAttribute()) ){
- InstConstantAttribute ica;
- ret.setAttribute(ica,in.getAttribute(InstConstantAttribute()) );
- }
Trace("quantifiers-rewrite") << "*** rewrite " << in << std::endl;
Trace("quantifiers-rewrite") << " to " << std::endl;
Trace("quantifiers-rewrite") << ret << std::endl;
@@ -311,7 +307,7 @@ Node QuantifiersRewriter::computeSimpleIteLift( Node body ) {
}
Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, Node& ipl ){
- Trace("var-elim-quant") << "Compute var elimination for " << body << std::endl;
+ Trace("var-elim-quant-debug") << "Compute var elimination for " << body << std::endl;
QuantPhaseReq qpr( body );
std::vector< Node > vars;
std::vector< Node > subs;
@@ -918,7 +914,7 @@ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption
}else if( computeOption==COMPUTE_NNF ){
return false;//TODO: compute NNF (current bad idea since arithmetic rewrites equalities)
}else if( computeOption==COMPUTE_SIMPLE_ITE_LIFT ){
- return !options::finiteModelFind();
+ return options::simpleIteLiftQuant();//!options::finiteModelFind();
}else if( computeOption==COMPUTE_PRENEX ){
return options::prenexQuant() && !options::aggressiveMiniscopeQuant();
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp
index 2b011552c..b079ae75c 100644..100755
--- a/src/theory/quantifiers/relevant_domain.cpp
+++ b/src/theory/quantifiers/relevant_domain.cpp
@@ -24,175 +24,159 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+void RelevantDomain::RDomain::merge( RDomain * r ) {
+ Assert( !d_parent );
+ Assert( !r->d_parent );
+ d_parent = r;
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ r->addTerm( d_terms[i] );
+ }
+ d_terms.clear();
+}
+
+void RelevantDomain::RDomain::addTerm( Node t ) {
+ if( std::find( d_terms.begin(), d_terms.end(), t )==d_terms.end() ){
+ d_terms.push_back( t );
+ }
+}
+
+RelevantDomain::RDomain * RelevantDomain::RDomain::getParent() {
+ if( !d_parent ){
+ return this;
+ }else{
+ RDomain * p = d_parent->getParent();
+ d_parent = p;
+ return p;
+ }
+}
+
+void RelevantDomain::RDomain::removeRedundantTerms( FirstOrderModel * fm ) {
+ std::map< Node, Node > rterms;
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Node r = d_terms[i];
+ if( !TermDb::hasInstConstAttr( d_terms[i] ) ){
+ r = fm->getRepresentative( d_terms[i] );
+ }
+ if( rterms.find( r )==rterms.end() ){
+ rterms[r] = d_terms[i];
+ }
+ }
+ d_terms.clear();
+ for( std::map< Node, Node >::iterator it = rterms.begin(); it != rterms.end(); ++it ){
+ d_terms.push_back( it->second );
+ }
+}
+
+
+
RelevantDomain::RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m ) : d_qe( qe ), d_model( m ){
}
+RelevantDomain::RDomain * RelevantDomain::getRDomain( Node n, int i ) {
+ if( d_rel_doms.find( n )==d_rel_doms.end() || d_rel_doms[n].find( i )==d_rel_doms[n].end() ){
+ d_rel_doms[n][i] = new RDomain;
+ d_rn_map[d_rel_doms[n][i]] = n;
+ d_ri_map[d_rel_doms[n][i]] = i;
+ }
+ return d_rel_doms[n][i]->getParent();
+}
+
void RelevantDomain::compute(){
- Trace("rel-dom") << "compute relevant domain" << std::endl;
- d_quant_inst_domain.clear();
+ for( std::map< Node, std::map< int, RDomain * > >::iterator it = d_rel_doms.begin(); it != d_rel_doms.end(); ++it ){
+ for( std::map< int, RDomain * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ it2->second->reset();
+ }
+ }
for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){
Node f = d_model->getAssertedQuantifier( i );
- d_quant_inst_domain[f].resize( f[0].getNumChildren() );
+ Node icf = d_qe->getTermDatabase()->getInstConstantBody( f );
+ Trace("rel-dom-debug") << "compute relevant domain for " << icf << std::endl;
+ computeRelevantDomain( icf, true, true );
}
- Trace("rel-dom") << "account for ground terms" << std::endl;
- //add ground terms to domain (rule 1 of complete instantiation essentially uf fragment)
- for( std::map< Node, uf::UfModelTree >::iterator it = d_model->d_uf_model_tree.begin();
- it != d_model->d_uf_model_tree.end(); ++it ){
+
+ Trace("rel-dom-debug") << "account for ground terms" << std::endl;
+ for( std::map< Node, std::vector< Node > >::iterator it = d_model->d_uf_terms.begin(); it != d_model->d_uf_terms.end(); ++it ){
Node op = it->first;
- for( size_t i=0; i<d_model->d_uf_terms[op].size(); i++ ){
- Node n = d_model->d_uf_terms[op][i];
- //add arguments to domain
- for( int j=0; j<(int)n.getNumChildren(); j++ ){
- if( d_model->d_rep_set.hasType( n[j].getType() ) ){
- Node ra = d_model->getRepresentative( n[j] );
- int raIndex = d_model->d_rep_set.getIndexFor( ra );
- if( raIndex==-1 ) Trace("rel-dom-warn") << "WARNING: Ground domain: rep set does not contain : " << ra << std::endl;
- Assert( raIndex!=-1 );
- if( std::find( d_active_domain[op][j].begin(), d_active_domain[op][j].end(), raIndex )==d_active_domain[op][j].end() ){
- d_active_domain[op][j].push_back( raIndex );
- }
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ //if it is a non-redundant term
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ RDomain * rf = getRDomain( op, j );
+ rf->addTerm( n[j] );
}
}
- //add to range
- Node r = d_model->getRepresentative( n );
- int raIndex = d_model->d_rep_set.getIndexFor( r );
- if( raIndex==-1 ) Trace("rel-dom-warn") << "WARNING: Ground range: rep set does not contain : " << r << std::endl;
- Assert( raIndex!=-1 );
- if( std::find( d_active_range[op].begin(), d_active_range[op].end(), raIndex )==d_active_range[op].end() ){
- d_active_range[op].push_back( raIndex );
- }
}
}
- Trace("rel-dom") << "do quantifiers" << std::endl;
- //find fixed point for relevant domain computation
- bool success;
- do{
- success = true;
- for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){
- Node f = d_model->getAssertedQuantifier( i );
- //compute the domain of relevant instantiations (rule 3 of complete instantiation, essentially uf fragment)
- if( computeRelevantInstantiationDomain( d_qe->getTermDatabase()->getInstConstantBody( f ), Node::null(), -1, f ) ){
- success = false;
- }
- //extend the possible domain for functions (rule 2 of complete instantiation, essentially uf fragment)
- RepDomain range;
- if( extendFunctionDomains( d_qe->getTermDatabase()->getInstConstantBody( f ), range ) ){
- success = false;
- }
- }
- }while( !success );
- Trace("rel-dom") << "done compute relevant domain" << std::endl;
- /*
- //debug printing
- Trace("rel-dom") << "Exhaustive instantiate " << f << std::endl;
- if( useRelInstDomain ){
- Trace("rel-dom") << "Relevant domain : " << std::endl;
- for( size_t i=0; i<d_rel_domain.d_quant_inst_domain[f].size(); i++ ){
- Trace("rel-dom") << " " << i << " : ";
- for( size_t j=0; j<d_rel_domain.d_quant_inst_domain[f][i].size(); j++ ){
- Trace("rel-dom") << d_rel_domain.d_quant_inst_domain[f][i][j] << " ";
+ //print debug
+ for( std::map< Node, std::map< int, RDomain * > >::iterator it = d_rel_doms.begin(); it != d_rel_doms.end(); ++it ){
+ Trace("rel-dom") << "Relevant domain for " << it->first << " : " << std::endl;
+ for( std::map< int, RDomain * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ Trace("rel-dom") << " " << it2->first << " : ";
+ RDomain * r = it2->second;
+ RDomain * rp = r->getParent();
+ if( r==rp ){
+ r->removeRedundantTerms( d_model );
+ for( unsigned i=0; i<r->d_terms.size(); i++ ){
+ Trace("rel-dom") << r->d_terms[i] << " ";
+ }
+ }else{
+ Trace("rel-dom") << "Dom( " << d_rn_map[rp] << ", " << d_ri_map[rp] << " ) ";
}
Trace("rel-dom") << std::endl;
}
}
- */
+
}
-bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, int arg, Node f ){
- bool domainChanged = false;
- if( n.getKind()==INST_CONSTANT ){
- bool domainSet = false;
- int vi = n.getAttribute(InstVarNumAttribute());
- Assert( !parent.isNull() );
- if( parent.getKind()==APPLY_UF ){
- //if the child of APPLY_UF term f( ... ), only consider the active domain of f at given argument
- Node op = parent.getOperator();
- if( d_active_domain.find( op )!=d_active_domain.end() ){
- for( size_t i=0; i<d_active_domain[op][arg].size(); i++ ){
- int d = d_active_domain[op][arg][i];
- if( std::find( d_quant_inst_domain[f][vi].begin(), d_quant_inst_domain[f][vi].end(), d )==
- d_quant_inst_domain[f][vi].end() ){
- d_quant_inst_domain[f][vi].push_back( d );
- domainChanged = true;
- }
- }
- domainSet = true;
- }
- }
- if( !domainSet ){
- //otherwise, we must consider the entire domain
- TypeNode tn = n.getType();
- if( d_quant_inst_domain_complete[f].find( vi )==d_quant_inst_domain_complete[f].end() ){
- if( d_model->d_rep_set.hasType( tn ) ){
- //it is the complete domain
- d_quant_inst_domain[f][vi].clear();
- for( size_t i=0; i<d_model->d_rep_set.d_type_reps[tn].size(); i++ ){
- d_quant_inst_domain[f][vi].push_back( i );
- }
- domainChanged = true;
+void RelevantDomain::computeRelevantDomain( Node n, bool hasPol, bool pol ) {
+
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n.getKind()==APPLY_UF ){
+ RDomain * rf = getRDomain( n.getOperator(), i );
+ if( n[i].getKind()==INST_CONSTANT ){
+ Node q = d_qe->getTermDatabase()->getInstConstAttr( n[i] );
+ //merge the RDomains
+ unsigned id = n[i].getAttribute(InstVarNumAttribute());
+ Trace("rel-dom-debug") << n[i] << " is variable # " << id << " for " << q;
+ Trace("rel-dom-debug") << " with body : " << d_qe->getTermDatabase()->getInstConstantBody( q ) << std::endl;
+ RDomain * rq = getRDomain( q, id );
+ if( rf!=rq ){
+ rq->merge( rf );
}
- d_quant_inst_domain_complete[f][vi] = true;
+ }else{
+ //term to add
+ rf->addTerm( n[i] );
}
}
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( computeRelevantInstantiationDomain( n[i], n, i, f ) ){
- domainChanged = true;
- }
+
+ //TODO
+ if( n[i].getKind()!=FORALL ){
+ bool newHasPol = hasPol;
+ bool newPol = pol;
+ computeRelevantDomain( n[i], newHasPol, newPol );
}
}
- return domainChanged;
}
-bool RelevantDomain::extendFunctionDomains( Node n, RepDomain& range ){
- if( n.getKind()==INST_CONSTANT ){
- Node f = n.getAttribute(InstConstantAttribute());
- int var = n.getAttribute(InstVarNumAttribute());
- range.insert( range.begin(), d_quant_inst_domain[f][var].begin(), d_quant_inst_domain[f][var].end() );
- return false;
+Node RelevantDomain::getRelevantTerm( Node f, int i, Node r ) {
+ RDomain * rf = getRDomain( f, i );
+ Trace("rel-dom-debug") << "Get relevant domain " << rf << " " << r << std::endl;
+ if( !d_qe->getEqualityQuery()->getEngine()->hasTerm( r ) || rf->hasTerm( r ) ){
+ return r;
}else{
- Node op;
- if( n.getKind()==APPLY_UF ){
- op = n.getOperator();
- }
- bool domainChanged = false;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- RepDomain childRange;
- if( extendFunctionDomains( n[i], childRange ) ){
- domainChanged = true;
- }
- if( n.getKind()==APPLY_UF ){
- if( d_active_domain.find( op )!=d_active_domain.end() ){
- for( int j=0; j<(int)childRange.size(); j++ ){
- int v = childRange[j];
- if( std::find( d_active_domain[op][i].begin(), d_active_domain[op][i].end(), v )==d_active_domain[op][i].end() ){
- d_active_domain[op][i].push_back( v );
- domainChanged = true;
- }
- }
- }else{
- //do this?
- }
- }
- }
- //get the range
- if( n.hasAttribute(InstConstantAttribute()) ){
- if( n.getKind()==APPLY_UF && d_active_range.find( op )!=d_active_range.end() ){
- range.insert( range.end(), d_active_range[op].begin(), d_active_range[op].end() );
- }else{
- //infinite range?
- }
- }else{
- Node r = d_model->getRepresentative( n );
- int index = d_model->d_rep_set.getIndexFor( r );
- if( index==-1 ){
- //we consider all ground terms in bodies of quantifiers to be the first ground representative
- range.push_back( 0 );
- }else{
- range.push_back( index );
+ Node rr = d_model->getRepresentative( r );
+ eq::EqClassIterator eqc( rr, d_qe->getEqualityQuery()->getEngine() );
+ while( !eqc.isFinished() ){
+ Node en = (*eqc);
+ if( rf->hasTerm( en ) ){
+ return en;
}
+ ++eqc;
}
- return domainChanged;
+ //otherwise, may be equal to some non-ground term
+
+ return r;
}
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h
index 6fc035e8a..c4345f828 100644..100755
--- a/src/theory/quantifiers/relevant_domain.h
+++ b/src/theory/quantifiers/relevant_domain.h
@@ -26,25 +26,33 @@ namespace quantifiers {
class RelevantDomain
{
private:
+ class RDomain
+ {
+ public:
+ RDomain() : d_parent( NULL ) {}
+ void reset() { d_parent = NULL; d_terms.clear(); }
+ RDomain * d_parent;
+ std::vector< Node > d_terms;
+ void merge( RDomain * r );
+ void addTerm( Node t );
+ RDomain * getParent();
+ void removeRedundantTerms( FirstOrderModel * fm );
+ bool hasTerm( Node n ) { return std::find( d_terms.begin(), d_terms.end(), n )!=d_terms.end(); }
+ };
+ std::map< Node, std::map< int, RDomain * > > d_rel_doms;
+ std::map< RDomain *, Node > d_rn_map;
+ std::map< RDomain *, int > d_ri_map;
+ RDomain * getRDomain( Node n, int i );
QuantifiersEngine* d_qe;
FirstOrderModel* d_model;
-
- //the domain of the arguments for each operator
- std::map< Node, std::map< int, RepDomain > > d_active_domain;
- //the range for each operator
- std::map< Node, RepDomain > d_active_range;
- //for computing relevant instantiation domain, return true if changed
- bool computeRelevantInstantiationDomain( Node n, Node parent, int arg, Node f );
- //for computing extended
- bool extendFunctionDomains( Node n, RepDomain& range );
+ void computeRelevantDomain( Node n, bool hasPol, bool pol );
public:
RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m );
virtual ~RelevantDomain(){}
//compute the relevant domain
void compute();
- //relevant instantiation domain for each quantifier
- std::map< Node, std::vector< RepDomain > > d_quant_inst_domain;
- std::map< Node, std::map< int, bool > > d_quant_inst_domain_complete;
+
+ Node getRelevantTerm( Node f, int i, Node r );
};/* class RelevantDomain */
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
new file mode 100755
index 000000000..107a99014
--- /dev/null
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -0,0 +1,184 @@
+/********************* */
+/*! \file bounded_integers.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Rewrite engine module
+ **
+ ** This class manages rewrite rules for quantifiers
+ **/
+
+#include "theory/quantifiers/rewrite_engine.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/inst_match_generator.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4;
+using namespace std;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+
+struct PrioritySort {
+ std::vector< double > d_priority;
+ bool operator() (int i,int j) {
+ return d_priority[i] < d_priority[j];
+ }
+};
+
+
+RewriteEngine::RewriteEngine( context::Context* c, QuantifiersEngine* qe ) : QuantifiersModule(qe) {
+
+}
+
+double RewriteEngine::getPriority( Node f ) {
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Node rrr = rr[2];
+ Trace("rr-priority") << "Get priority : " << rrr << " " << rrr.getKind() << std::endl;
+ bool deterministic = rrr[1].getKind()!=OR;
+ if( rrr.getKind()==RR_REWRITE ){
+ return deterministic ? 0.0 : 3.0;
+ }else if( rrr.getKind()==RR_DEDUCTION ){
+ return deterministic ? 1.0 : 4.0;
+ }else if( rrr.getKind()==RR_REDUCTION ){
+ return deterministic ? 2.0 : 5.0;
+ }else{
+ return 6.0;
+ }
+}
+
+void RewriteEngine::check( Theory::Effort e ) {
+ if( e==Theory::EFFORT_LAST_CALL ){
+ if( !d_quantEngine->getModel()->isModelSet() ){
+ d_quantEngine->getTheoryEngine()->getModelBuilder()->buildModel( d_quantEngine->getModel(), true );
+ }
+ if( d_true.isNull() ){
+ d_true = NodeManager::currentNM()->mkConst( true );
+ }
+ std::vector< Node > priority_order;
+ PrioritySort ps;
+ std::vector< int > indicies;
+ for( int i=0; i<(int)d_rr_quant.size(); i++ ){
+ ps.d_priority.push_back( getPriority( d_rr_quant[i] ) );
+ indicies.push_back( i );
+ }
+ std::sort( indicies.begin(), indicies.end(), ps );
+ for( unsigned i=0; i<indicies.size(); i++ ){
+ priority_order.push_back( d_rr_quant[indicies[i]] );
+ }
+
+ //apply rewrite rules
+ int addedLemmas = 0;
+ //per priority level
+ int index = 0;
+ bool success = true;
+ while( success && index<(int)priority_order.size() ) {
+ addedLemmas += checkRewriteRule( priority_order[index] );
+ index++;
+ if( index<(int)priority_order.size() ){
+ success = addedLemmas==0 || getPriority( priority_order[index] )==getPriority( priority_order[index-1] );
+ }
+ }
+
+ Trace("inst-engine") << "Rewrite engine added " << addedLemmas << " lemmas." << std::endl;
+ if (addedLemmas==0) {
+ }else{
+ //otherwise, the search will continue
+ d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
+ }
+ }
+}
+
+int RewriteEngine::checkRewriteRule( Node f ) {
+ Trace("rewrite-engine-inst") << "Check " << f << ", priority = " << getPriority( f ) << "..." << std::endl;
+ int addedLemmas = 0;
+ //reset triggers
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ if( d_rr_triggers.find(f)==d_rr_triggers.end() ){
+ std::vector< inst::Trigger * > triggers;
+ if( f.getNumChildren()==3 ){
+ for(unsigned i=0; i<f[2].getNumChildren(); i++ ){
+ Node pat = f[2][i];
+ std::vector< Node > nodes;
+ Trace("rewrite-engine-trigger") << "Trigger is : ";
+ for( int j=0; j<(int)pat.getNumChildren(); j++ ){
+ Node p = d_quantEngine->getTermDatabase()->getInstConstantNode( pat[j], f );
+ nodes.push_back( p );
+ Trace("rewrite-engine-trigger") << p << " " << p.getKind() << " ";
+ }
+ Trace("rewrite-engine-trigger") << std::endl;
+ Assert( inst::Trigger::isUsableTrigger( nodes, f ) );
+ inst::Trigger * tr = inst::Trigger::mkTrigger( d_quantEngine, f, nodes, 0, true, inst::Trigger::TR_MAKE_NEW, false );
+ tr->getGenerator()->setActiveAdd(false);
+ triggers.push_back( tr );
+ }
+ }
+ d_rr_triggers[f].insert( d_rr_triggers[f].end(), triggers.begin(), triggers.end() );
+ }
+ for( unsigned i=0; i<d_rr_triggers[f].size(); i++ ){
+ Trace("rewrite-engine-inst") << "Try trigger " << *d_rr_triggers[f][i] << std::endl;
+ d_rr_triggers[f][i]->resetInstantiationRound();
+ d_rr_triggers[f][i]->reset( Node::null() );
+ bool success;
+ do
+ {
+ InstMatch m;
+ success = d_rr_triggers[f][i]->getNextMatch( f, m );
+ if( success ){
+ //see if instantiation is true in the model
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Node rrg = rr[1];
+ std::vector< Node > vars;
+ std::vector< Node > terms;
+ d_quantEngine->computeTermVector( f, m, vars, terms );
+ Trace("rewrite-engine-inst-debug") << "Instantiation : " << m << std::endl;
+ Node inst = d_rr_guard[f];
+ inst = inst.substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
+ Trace("rewrite-engine-inst-debug") << "Try instantiation, guard : " << inst << std::endl;
+ FirstOrderModel * fm = d_quantEngine->getModel();
+ Node v = fm->getValue( inst );
+ Trace("rewrite-engine-inst-debug") << "Evaluated to " << v << std::endl;
+ if( v==d_true ){
+ Trace("rewrite-engine-inst-debug") << "Add instantiation : " << m << std::endl;
+ if( d_quantEngine->addInstantiation( f, m ) ){
+ addedLemmas++;
+ Trace("rewrite-engine-inst-debug") << "success" << std::endl;
+ //set the no-match attribute (the term is rewritten and can be ignored)
+ //Trace("rewrite-engine-inst-debug") << "We matched on : " << m.d_matched << std::endl;
+ //if( !m.d_matched.isNull() ){
+ // NoMatchAttribute nma;
+ // m.d_matched.setAttribute(nma,true);
+ //}
+ }else{
+ Trace("rewrite-engine-inst-debug") << "failure." << std::endl;
+ }
+ }
+ }
+ }while(success);
+ }
+ Trace("rewrite-engine-inst") << "Rule " << f << " generated " << addedLemmas << " lemmas." << std::endl;
+ return addedLemmas;
+}
+
+void RewriteEngine::registerQuantifier( Node f ) {
+ if( f.hasAttribute(QRewriteRuleAttribute()) ){
+ Trace("rewrite-engine") << "Register quantifier " << f << std::endl;
+ Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Trace("rewrite-engine") << " rewrite rule is : " << rr << std::endl;
+ d_rr_quant.push_back( f );
+ d_rr_guard[f] = rr[1];
+ Trace("rewrite-engine") << " guard is : " << d_rr_guard[f] << std::endl;
+ }
+}
+
+void RewriteEngine::assertNode( Node n ) {
+
+}
+
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
new file mode 100755
index 000000000..2d9d751c2
--- /dev/null
+++ b/src/theory/quantifiers/rewrite_engine.h
@@ -0,0 +1,54 @@
+/********************* */
+/*! \file bounded_integers.h
+** \verbatim
+** Original author: Andrew Reynolds
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2013 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief This class manages integer bounds for quantifiers
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__REWRITE_ENGINE_H
+#define __CVC4__REWRITE_ENGINE_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/trigger.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class RewriteEngine : public QuantifiersModule
+{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+ std::vector< Node > d_rr_quant;
+ std::map< Node, Node > d_rr_guard;
+ Node d_true;
+ /** explicitly provided patterns */
+ std::map< Node, std::vector< inst::Trigger* > > d_rr_triggers;
+ double getPriority( Node f );
+private:
+ int checkRewriteRule( Node f );
+public:
+ RewriteEngine( context::Context* c, QuantifiersEngine* qe );
+
+ void check( Theory::Effort e );
+ void registerQuantifier( Node f );
+ void assertNode( Node n );
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp
new file mode 100755
index 000000000..507a50838
--- /dev/null
+++ b/src/theory/quantifiers/symmetry_breaking.cpp
@@ -0,0 +1,314 @@
+/********************* */
+/*! \file symmetry_breaking.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief symmetry breaking module
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/symmetry_breaking.h"
+#include "theory/rewriter.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+#include "util/sort_inference.h"
+#include "theory/uf/theory_uf_strong_solver.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace std;
+
+namespace CVC4 {
+
+
+SubsortSymmetryBreaker::SubsortSymmetryBreaker(QuantifiersEngine* qe, context::Context* c) :
+d_qe(qe), d_conflict(c,false) {
+ d_true = NodeManager::currentNM()->mkConst( true );
+}
+
+eq::EqualityEngine * SubsortSymmetryBreaker::getEqualityEngine() {
+ return ((uf::TheoryUF*)d_qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
+}
+
+bool SubsortSymmetryBreaker::areEqual( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
+}
+
+bool SubsortSymmetryBreaker::areDisequal( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
+}
+
+
+Node SubsortSymmetryBreaker::getRepresentative( Node n ) {
+ return getEqualityEngine()->getRepresentative( n );
+}
+
+uf::StrongSolverTheoryUF * SubsortSymmetryBreaker::getStrongSolver() {
+ return ((uf::TheoryUF*)d_qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getStrongSolver();
+}
+
+SubsortSymmetryBreaker::TypeInfo::TypeInfo( context::Context * c ) :
+d_max_dom_const_sort(c,0), d_has_dom_const_sort(c,false) {
+}
+
+SubsortSymmetryBreaker::SubSortInfo::SubSortInfo( context::Context * c ) :
+d_dom_constants( c ), d_first_active( c, 0 ){
+ d_dc_nodes = 0;
+}
+
+unsigned SubsortSymmetryBreaker::SubSortInfo::getNumDomainConstants() {
+ if( d_nodes.empty() ){
+ return 0;
+ }else{
+ return 1 + d_dom_constants.size();
+ }
+}
+
+Node SubsortSymmetryBreaker::SubSortInfo::getDomainConstant( int i ) {
+ if( i==0 ){
+ return d_nodes[0];
+ }else{
+ Assert( i<=(int)d_dom_constants.size() );
+ return d_dom_constants[i-1];
+ }
+}
+
+Node SubsortSymmetryBreaker::SubSortInfo::getFirstActive(eq::EqualityEngine * ee) {
+ if( d_first_active.get()<(int)d_nodes.size() ){
+ Node fa = d_nodes[d_first_active.get()];
+ return ee->hasTerm( fa ) ? fa : Node::null();
+ }else{
+ return Node::null();
+ }
+}
+
+SubsortSymmetryBreaker::TypeInfo * SubsortSymmetryBreaker::getTypeInfo( TypeNode tn ) {
+ if( d_t_info.find( tn )==d_t_info.end() ){
+ d_t_info[tn] = new TypeInfo( d_qe->getSatContext() );
+ }
+ return d_t_info[tn];
+}
+
+SubsortSymmetryBreaker::SubSortInfo * SubsortSymmetryBreaker::getSubSortInfo( TypeNode tn, int sid ) {
+ if( d_type_info.find( sid )==d_type_info.end() ){
+ d_type_info[sid] = new SubSortInfo( d_qe->getSatContext() );
+ d_sub_sorts[tn].push_back( sid );
+ d_sid_to_type[sid] = tn;
+ }
+ return d_type_info[sid];
+}
+
+void SubsortSymmetryBreaker::newEqClass( Node n ) {
+ Trace("sym-break-temp") << "New eq class " << n << std::endl;
+ if( !d_conflict ){
+ TypeNode tn = n.getType();
+ SortInference * si = d_qe->getTheoryEngine()->getSortInference();
+ if( si->isWellSorted( n ) ){
+ int sid = si->getSortId( n );
+ Trace("sym-break-debug") << "SSB: New eq class " << n << " : " << n.getType() << " : " << sid << std::endl;
+ SubSortInfo * ti = getSubSortInfo( tn, sid );
+ if( std::find( ti->d_nodes.begin(), ti->d_nodes.end(), n )==ti->d_nodes.end() ){
+ if( ti->d_nodes.empty() ){
+ //for first subsort, we add unit equality
+ if( d_sub_sorts[tn][0]!=sid ){
+ Trace("sym-break-temp") << "Do sym break unit with " << d_type_info[d_sub_sorts[tn][0]]->getBaseConstant() << std::endl;
+ //add unit symmetry breaking lemma
+ Node eq = n.eqNode( d_type_info[d_sub_sorts[tn][0]]->getBaseConstant() );
+ eq = Rewriter::rewrite( eq );
+ d_unit_lemmas.push_back( eq );
+ Trace("sym-break-lemma") << "*** SymBreak : Unit lemma (" << sid << "==" << d_sub_sorts[tn][0] << ") : " << eq << std::endl;
+ d_pending_lemmas.push_back( eq );
+ }
+ Trace("sym-break-dc") << "* Set first domain constant : " << n << " for " << tn << " : " << sid << std::endl;
+ ti->d_dc_nodes++;
+ }
+ ti->d_node_to_id[n] = ti->d_nodes.size();
+ ti->d_nodes.push_back( n );
+ }
+ TypeInfo * tti = getTypeInfo( tn );
+ if( !tti->d_has_dom_const_sort.get() ){
+ tti->d_has_dom_const_sort.set( true );
+ tti->d_max_dom_const_sort.set( sid );
+ }
+ }
+ }
+ Trace("sym-break-temp") << "Done new eq class" << std::endl;
+}
+
+
+
+void SubsortSymmetryBreaker::merge( Node a, Node b ) {
+ if( Trace.isOn("sym-break-debug") ){
+ SortInference * si = d_qe->getTheoryEngine()->getSortInference();
+ int as = si->getSortId( a );
+ int bs = si->getSortId( b );
+ Trace("sym-break-debug") << "SSB: New merge " << a.getType() << " :: " << a << " : " << as;
+ Trace("sym-break-debug") << " == " << b << " : " << bs << std::endl;
+ }
+}
+
+void SubsortSymmetryBreaker::assertDisequal( Node a, Node b ) {
+ if( Trace.isOn("sym-break-debug") ){
+ SortInference * si = d_qe->getTheoryEngine()->getSortInference();
+ int as = si->getSortId( a );
+ int bs = si->getSortId( b );
+ Trace("sym-break-debug") << "SSB: New assert disequal " << a.getType() << " :: " << a << " : " << as;
+ Trace("sym-break-debug") << " != " << b << " : " << bs << std::endl;
+ }
+}
+
+void SubsortSymmetryBreaker::processFirstActive( TypeNode tn, int sid, int curr_card ){
+ SubSortInfo * ti = getSubSortInfo( tn, sid );
+ if( (int)ti->getNumDomainConstants()<curr_card ){
+ //static int checkCount = 0;
+ //checkCount++;
+ //if( checkCount%1000==0 ){
+ // std::cout << "Check count = " << checkCount << std::endl;
+ //}
+
+ Trace("sym-break-dc-debug") << "Check for domain constants " << tn << " : " << sid << ", curr_card = " << curr_card << ", ";
+ Trace("sym-break-dc-debug") << "#domain constants = " << ti->getNumDomainConstants() << std::endl;
+ Node fa = ti->getFirstActive(getEqualityEngine());
+ bool invalid = true;
+ while( invalid && !fa.isNull() && (int)ti->getNumDomainConstants()<curr_card ){
+ invalid = false;
+ unsigned deq = 0;
+ for( unsigned i=0; i<ti->getNumDomainConstants(); i++ ){
+ Node dc = ti->getDomainConstant( i );
+ if( areEqual( fa, dc ) ){
+ invalid = true;
+ break;
+ }else if( areDisequal( fa, dc ) ){
+ deq++;
+ }
+ }
+ if( deq==ti->getNumDomainConstants() ){
+ Trace("sym-break-dc") << "* Can infer domain constant #" << ti->getNumDomainConstants()+1;
+ Trace("sym-break-dc") << " : " << fa << " for " << tn << " : " << sid << std::endl;
+ //add to domain constants
+ ti->d_dom_constants.push_back( fa );
+ if( ti->d_node_to_id[fa]>ti->d_dc_nodes ){
+ Trace("sym-break-dc-debug") << "Swap nodes... " << ti->d_dc_nodes << " " << ti->d_node_to_id[fa] << " " << ti->d_nodes.size() << std::endl;
+ //swap
+ Node on = ti->d_nodes[ti->d_dc_nodes];
+ int id = ti->d_node_to_id[fa];
+
+ ti->d_nodes[ti->d_dc_nodes] = fa;
+ ti->d_nodes[id] = on;
+ ti->d_node_to_id[fa] = ti->d_dc_nodes;
+ ti->d_node_to_id[on] = id;
+ }
+ ti->d_dc_nodes++;
+ Trace("sym-break-dc-debug") << "Get max type info..." << std::endl;
+ TypeInfo * tti = getTypeInfo( tn );
+ Assert( tti->d_has_dom_const_sort.get() );
+ int msid = tti->d_max_dom_const_sort.get();
+ SubSortInfo * max_ti = getSubSortInfo( d_sid_to_type[msid], msid );
+ Trace("sym-break-dc-debug") << "Swap nodes..." << std::endl;
+ //now, check if we can apply symmetry breaking to another sort
+ if( ti->getNumDomainConstants()>max_ti->getNumDomainConstants() ){
+ Trace("sym-break-dc") << "Max domain constant subsort for " << tn << " becomes " << sid << std::endl;
+ tti->d_max_dom_const_sort.set( sid );
+ }else if( ti!=max_ti ){
+ //construct symmetry breaking lemma
+ //current domain constant must be disequal from all current ones
+ Trace("sym-break-dc") << "Get domain constant " << ti->getNumDomainConstants()-1;
+ Trace("sym-break-dc") << " from max_ti, " << max_ti->getNumDomainConstants() << std::endl;
+ //apply a symmetry breaking lemma
+ Node m = max_ti->getDomainConstant(ti->getNumDomainConstants()-1);
+ //if fa and m are disequal from all previous domain constants in the other sort
+ std::vector< Node > cc;
+ for( unsigned r=0; r<2; r++ ){
+ Node n = ((r==0)==(msid>sid)) ? fa : m;
+ Node on = ((r==0)==(msid>sid)) ? m : fa;
+ SubSortInfo * t = ((r==0)==(msid>sid)) ? max_ti : ti;
+ for( unsigned i=0; i<t->d_node_to_id[on]; i++ ){
+ cc.push_back( n.eqNode( t->d_nodes[i] ) );
+ }
+ }
+ //then, we can assume fa = m
+ cc.push_back( fa.eqNode( m ) );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, cc );
+ lem = Rewriter::rewrite( lem );
+ if( std::find( d_lemmas.begin(), d_lemmas.end(), lem )==d_lemmas.end() ){
+ d_lemmas.push_back( lem );
+ Trace("sym-break-lemma") << "*** Symmetry break lemma for " << tn << " (" << sid << "==" << tti->d_max_dom_const_sort.get() << ") : ";
+ Trace("sym-break-lemma") << lem << std::endl;
+ d_pending_lemmas.push_back( lem );
+ }
+ }
+ invalid = true;
+ }
+ if( invalid ){
+ ti->d_first_active.set( ti->d_first_active + 1 );
+ fa = ti->getFirstActive(getEqualityEngine());
+ }
+ }
+ }
+}
+
+void SubsortSymmetryBreaker::printDebugSubSortInfo( const char * c, TypeNode tn, int sid ) {
+ Trace(c) << "SubSortInfo( " << tn << ", " << sid << " ) = " << std::endl;
+ Trace(c) << " Domain constants : ";
+ SubSortInfo * ti = getSubSortInfo( tn, sid );
+ for( NodeList::const_iterator it = ti->d_dom_constants.begin(); it != ti->d_dom_constants.end(); ++it ){
+ Node dc = *it;
+ Trace(c) << dc << " ";
+ }
+ Trace(c) << std::endl;
+ Trace(c) << " First active node : " << ti->getFirstActive(getEqualityEngine()) << std::endl;
+}
+
+bool SubsortSymmetryBreaker::check( Theory::Effort level ) {
+
+ Trace("sym-break-debug") << "SymBreak : check " << level << std::endl;
+ /*
+ while( d_fact_index.get()<d_fact_list.size() ){
+ Node f = d_fact_list[d_fact_index.get()];
+ d_fact_index.set( d_fact_index.get() + 1 );
+ if( f.getKind()==EQUAL ){
+ merge( f[0], f[1] );
+ }else if( f.getKind()==NOT && f[0].getKind()==EQUAL ){
+ assertDisequal( f[0][0], f[0][1] );
+ }else{
+ newEqClass( f );
+ }
+ }
+ */
+ Trace("sym-break-debug") << "SymBreak : update first actives" << std::endl;
+ for( std::map< TypeNode, std::vector< int > >::iterator it = d_sub_sorts.begin(); it != d_sub_sorts.end(); ++it ){
+ int card = getStrongSolver()->getCardinality( it->first );
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ //check if the first active is disequal from all domain constants
+ processFirstActive( it->first, it->second[i], card );
+ }
+ }
+
+
+ Trace("sym-break-debug") << "SymBreak : finished check, now flush lemmas... (#lemmas = " << d_pending_lemmas.size() << ")" << std::endl;
+ //flush pending lemmas
+ if( !d_pending_lemmas.empty() ){
+ for( unsigned i=0; i<d_pending_lemmas.size(); i++ ){
+ getStrongSolver()->getOutputChannel().lemma( d_pending_lemmas[i] );
+ ++( getStrongSolver()->d_statistics.d_sym_break_lemmas );
+ }
+ d_pending_lemmas.clear();
+ return true;
+ }else{
+ return false;
+ }
+}
+
+
+
+}
+
diff --git a/src/theory/quantifiers/symmetry_breaking.h b/src/theory/quantifiers/symmetry_breaking.h
new file mode 100755
index 000000000..05461d378
--- /dev/null
+++ b/src/theory/quantifiers/symmetry_breaking.h
@@ -0,0 +1,118 @@
+/********************* */
+/*! \file symmetry_breaking.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Pre-process step for first-order reasoning
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__QUANT_SYMMETRY_BREAKING_H
+#define __CVC4__QUANT_SYMMETRY_BREAKING_H
+
+#include "theory/theory.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+#include "expr/node.h"
+#include "expr/type_node.h"
+
+#include "util/sort_inference.h"
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+
+namespace uf {
+ class StrongSolverTheoryUF;
+}
+
+class SubsortSymmetryBreaker {
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+ //typedef context::CDChunkList<int> IntList;
+ typedef context::CDList<Node> NodeList;
+ typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
+private:
+ /** quantifiers engine */
+ QuantifiersEngine* d_qe;
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( Node n1, Node n2 );
+ bool areEqual( Node n1, Node n2 );
+ Node getRepresentative( Node n );
+ uf::StrongSolverTheoryUF * getStrongSolver();
+ std::vector< Node > d_unit_lemmas;
+ Node d_true;
+ context::CDO< bool > d_conflict;
+public:
+ SubsortSymmetryBreaker( QuantifiersEngine* qe, context::Context* c );
+ ~SubsortSymmetryBreaker(){}
+
+private:
+ class TypeInfo {
+ public:
+ TypeInfo( context::Context* c );
+ context::CDO< int > d_max_dom_const_sort;
+ context::CDO< bool > d_has_dom_const_sort;
+ };
+ class SubSortInfo {
+ public:
+ SubSortInfo( context::Context* c );
+ //list of all nodes from this (sub)type
+ std::vector< Node > d_nodes;
+ //the current domain constants for this (sub)type
+ NodeList d_dom_constants;
+ //# nodes in d_nodes that have been domain constants, size of this distinct # of domain constants seen
+ unsigned d_dc_nodes;
+ //the node we are currently watching to become a domain constant
+ context::CDO< int > d_first_active;
+ //node to id
+ std::map< Node, unsigned > d_node_to_id;
+ Node getBaseConstant() { return d_nodes.empty() ? Node::null() : d_nodes[0]; }
+ bool hasDomainConstant( Node n );
+ unsigned getNumDomainConstants();
+ Node getDomainConstant( int i );
+ Node getFirstActive(eq::EqualityEngine * ee);
+ };
+ std::map< TypeNode, std::vector< int > > d_sub_sorts;
+ std::map< int, TypeNode > d_sid_to_type;
+ std::map< TypeNode, TypeInfo * > d_t_info;
+ std::map< int, SubSortInfo * > d_type_info;
+
+ TypeInfo * getTypeInfo( TypeNode tn );
+ SubSortInfo * getSubSortInfo( TypeNode tn, int sid );
+
+ void processFirstActive( TypeNode tn, int sid, int curr_card );
+private:
+ //void printDebugNodeInfo( const char * c, Node n );
+ void printDebugSubSortInfo( const char * c, TypeNode tn, int sid );
+ /** fact list */
+ std::vector< Node > d_pending_lemmas;
+ std::vector< Node > d_lemmas;
+public:
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert disequal */
+ void assertDisequal( Node a, Node b );
+ /** check */
+ bool check( Theory::Effort level );
+};
+
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 3153a3c64..e18a4e0dc 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -74,7 +74,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
//if this is an atomic trigger, consider adding it
//Call the children?
if( inst::Trigger::isAtomicTrigger( n ) ){
- if( !n.hasAttribute(InstConstantAttribute()) ){
+ if( !TermDb::hasInstConstAttr(n) ){
Trace("term-db") << "register term in db " << n << std::endl;
//std::cout << "register trigger term " << n << std::endl;
Node op = n.getOperator();
@@ -117,7 +117,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
}
}
}else{
- if( options::efficientEMatching() && !n.hasAttribute(InstConstantAttribute())){
+ if( options::efficientEMatching() && !TermDb::hasInstConstAttr(n)){
//Efficient e-matching must be notified
//The term in triggers are not important here
Debug("term-db") << "New in this branch term " << n << std::endl;
@@ -167,7 +167,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
while( !eqc.isFinished() ){
Node en = (*eqc);
computeModelBasisArgAttribute( en );
- if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){
+ if( en.getKind()==APPLY_UF && !TermDb::hasInstConstAttr(en) ){
if( !en.getAttribute(NoMatchAttribute()) ){
Node op = en.getOperator();
if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
@@ -194,14 +194,20 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
Node mbt;
- if( options::fmfFreshDistConst() || d_type_map[ tn ].empty() ){
- std::stringstream ss;
- ss << Expr::setlanguage(options::outputLanguage());
- ss << "e_" << tn;
- mbt = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "is a model basis term" );
- Trace("mkVar") << "ModelBasis:: Make variable " << mbt << " : " << tn << std::endl;
+ if( tn.isInteger() || tn.isReal() ){
+ mbt = NodeManager::currentNM()->mkConst( Rational( 0 ) );
+ }else if( !tn.isSort() ){
+ mbt = tn.mkGroundTerm();
}else{
- mbt = d_type_map[ tn ][ 0 ];
+ if( options::fmfFreshDistConst() || d_type_map[ tn ].empty() ){
+ std::stringstream ss;
+ ss << Expr::setlanguage(options::outputLanguage());
+ ss << "e_" << tn;
+ mbt = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "is a model basis term" );
+ Trace("mkVar") << "ModelBasis:: Make variable " << mbt << " : " << tn << std::endl;
+ }else{
+ mbt = d_type_map[ tn ][ 0 ];
+ }
}
ModelBasisAttribute mba;
mbt.setAttribute(mba,true);
@@ -254,8 +260,7 @@ void TermDb::computeModelBasisArgAttribute( Node n ){
//determine if it has model basis attribute
for( int j=0; j<(int)n.getNumChildren(); j++ ){
if( n[j].getAttribute(ModelBasisAttribute()) ){
- val = 1;
- break;
+ val++;
}
}
ModelBasisArgAttribute mbaa;
@@ -276,33 +281,75 @@ void TermDb::makeInstantiationConstantsFor( Node f ){
//set the var number attribute
InstVarNumAttribute ivna;
ic.setAttribute(ivna,i);
+ InstConstantAttribute ica;
+ ic.setAttribute(ica,f);
+ //also set the no-match attribute
+ NoMatchAttribute nma;
+ ic.setAttribute(nma,true);
}
}
}
-void TermDb::setInstantiationConstantAttr( Node n, Node f ){
- if( !n.hasAttribute(InstConstantAttribute()) ){
- bool setAttr = false;
- if( n.getKind()==INST_CONSTANT ){
- setAttr = true;
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- setInstantiationConstantAttr( n[i], f );
- if( n[i].hasAttribute(InstConstantAttribute()) ){
- setAttr = true;
- }
+
+Node TermDb::getInstConstAttr( Node n ) {
+ if (!n.hasAttribute(InstConstantAttribute()) ){
+ Node f;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ f = getInstConstAttr(n[i]);
+ if( !f.isNull() ){
+ break;
}
}
- if( setAttr ){
- InstConstantAttribute ica;
- n.setAttribute(ica,f);
+ InstConstantAttribute ica;
+ n.setAttribute(ica,f);
+ if( !f.isNull() ){
//also set the no-match attribute
NoMatchAttribute nma;
n.setAttribute(nma,true);
}
}
+ return n.getAttribute(InstConstantAttribute());
+}
+
+bool TermDb::hasInstConstAttr( Node n ) {
+ return !getInstConstAttr(n).isNull();
+}
+
+bool TermDb::hasBoundVarAttr( Node n ) {
+ if( !n.getAttribute(HasBoundVarComputedAttribute()) ){
+ bool hasBv = false;
+ if( n.getKind()==BOUND_VARIABLE ){
+ hasBv = true;
+ }else{
+ for (unsigned i=0; i<n.getNumChildren(); i++) {
+ if( hasBoundVarAttr(n[i]) ){
+ hasBv = true;
+ break;
+ }
+ }
+ }
+ HasBoundVarAttribute hbva;
+ n.setAttribute(hbva, hasBv);
+ HasBoundVarComputedAttribute hbvca;
+ n.setAttribute(hbvca, true);
+ Trace("bva") << n << " has bva : " << n.getAttribute(HasBoundVarAttribute()) << std::endl;
+ }
+ return n.getAttribute(HasBoundVarAttribute());
+}
+
+void TermDb::getBoundVars( Node n, std::vector< Node >& bvs) {
+ if (n.getKind()==BOUND_VARIABLE ){
+ if ( std::find( bvs.begin(), bvs.end(), n)==bvs.end() ){
+ bvs.push_back( n );
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ getBoundVars(n[i], bvs);
+ }
+ }
}
+
/** get the i^th instantiation constant of f */
Node TermDb::getInstantiationConstant( Node f, int i ) const {
std::map< Node, std::vector< Node > >::const_iterator it = d_inst_constants.find( f );
@@ -348,7 +395,6 @@ Node TermDb::getCounterexampleLiteral( Node f ){
//otherwise, ensure literal
Node ceLit = d_quantEngine->getValuation().ensureLiteral( ceBody.notNode() );
d_ce_lit[ f ] = ceLit;
- setInstantiationConstantAttr( ceLit, f );
}
return d_ce_lit[ f ];
}
@@ -362,7 +408,6 @@ Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector<Node> & var
Node n2 = n.substitute( vars.begin(), vars.end(),
inst_constants.begin(),
inst_constants.end() );
- setInstantiationConstantAttr( n2, f );
return n2;
}
@@ -390,16 +435,19 @@ Node TermDb::getSkolemizedBody( Node f ){
Node TermDb::getFreeVariableForInstConstant( Node n ){
TypeNode tn = n.getType();
if( d_free_vars.find( tn )==d_free_vars.end() ){
- //if integer or real, make zero
- if( tn.isInteger() || tn.isReal() ){
- Rational z(0);
- d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
- }else{
- if( d_type_map[ tn ].empty() ){
- d_free_vars[tn] = NodeManager::currentNM()->mkSkolem( "freevar_$$", tn, "is a free variable created by termdb" );
- Trace("mkVar") << "FreeVar:: Make variable " << d_free_vars[tn] << " : " << tn << std::endl;
+ for( unsigned i=0; i<d_type_map[ tn ].size(); i++ ){
+ if( !quantifiers::TermDb::hasInstConstAttr(d_type_map[ tn ][ i ]) ){
+ d_free_vars[tn] = d_type_map[ tn ][ i ];
+ }
+ }
+ if( d_free_vars.find( tn )==d_free_vars.end() ){
+ //if integer or real, make zero
+ if( tn.isInteger() || tn.isReal() ){
+ Rational z(0);
+ d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
}else{
- d_free_vars[tn] = d_type_map[ tn ][ 0 ];
+ d_free_vars[tn] = NodeManager::currentNM()->mkSkolem( "freevar_$$", tn, "is a free variable created by termdb" );
+ Trace("mkVar") << "FreeVar:: Make variable " << d_free_vars[tn] << " : " << tn << std::endl;
}
}
}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index 231d0ee9e..1688479f3 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -59,6 +59,19 @@ typedef expr::Attribute<ModelBasisAttributeId, bool> ModelBasisAttribute;
struct ModelBasisArgAttributeId {};
typedef expr::Attribute<ModelBasisArgAttributeId, uint64_t> ModelBasisArgAttribute;
+struct HasBoundVarAttributeId {};
+typedef expr::Attribute<HasBoundVarAttributeId, bool> HasBoundVarAttribute;
+struct HasBoundVarComputedAttributeId {};
+typedef expr::Attribute<HasBoundVarComputedAttributeId, bool> HasBoundVarComputedAttribute;
+
+//for rewrite rules
+struct QRewriteRuleAttributeId {};
+typedef expr::Attribute<QRewriteRuleAttributeId, Node> QRewriteRuleAttribute;
+
+//for bounded integers
+struct BoundIntLitAttributeId {};
+typedef expr::Attribute<BoundIntLitAttributeId, uint64_t> BoundIntLitAttribute;
+
class QuantifiersEngine;
@@ -83,10 +96,15 @@ public:
};/* class TermArgTrie */
+namespace fmcheck {
+ class FullModelChecker;
+}
+
class TermDb {
friend class ::CVC4::theory::QuantifiersEngine;
friend class ::CVC4::theory::inst::Trigger;
friend class ::CVC4::theory::rrinst::Trigger;
+ friend class ::CVC4::theory::quantifiers::fmcheck::FullModelChecker;
private:
/** reference to the quantifiers engine */
QuantifiersEngine* d_quantEngine;
@@ -181,9 +199,15 @@ public:
Node convertNodeToPattern( Node n, Node f,
const std::vector<Node> & vars,
const std::vector<Node> & nvars);
- /** set instantiation constant attr */
- void setInstantiationConstantAttr( Node n, Node f );
+ static Node getInstConstAttr( Node n );
+ static bool hasInstConstAttr( Node n );
+//for bound variables
+public:
+ //does n have bound variables?
+ static bool hasBoundVarAttr( Node n );
+ //get bound variables in n
+ static void getBoundVars( Node n, std::vector< Node >& bvs);
//for skolem
private:
/** map from universal quantifiers to the list of skolem constants */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 9843cd09e..066282c2c 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -65,7 +65,7 @@ void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) {
void TheoryQuantifiers::preRegisterTerm(TNode n) {
Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl;
- if( n.getKind()==FORALL && !n.hasAttribute(InstConstantAttribute()) ){
+ if( n.getKind()==FORALL && !TermDb::hasInstConstAttr(n) ){
getQuantifiersEngine()->registerQuantifier( n );
}
}
@@ -149,7 +149,7 @@ Node TheoryQuantifiers::getNextDecisionRequest(){
void TheoryQuantifiers::assertUniversal( Node n ){
Assert( n.getKind()==FORALL );
- if( !n.hasAttribute(InstConstantAttribute()) ){
+ if( options::recurseCbqi() || !TermDb::hasInstConstAttr(n) ){
getQuantifiersEngine()->registerQuantifier( n );
getQuantifiersEngine()->assertNode( n );
}
@@ -157,13 +157,13 @@ void TheoryQuantifiers::assertUniversal( Node n ){
void TheoryQuantifiers::assertExistential( Node n ){
Assert( n.getKind()== NOT && n[0].getKind()==FORALL );
- if( !n[0].hasAttribute(InstConstantAttribute()) ){
+ if( options::recurseCbqi() || !TermDb::hasInstConstAttr(n[0]) ){
if( d_skolemized.find( n )==d_skolemized.end() ){
Node body = getQuantifiersEngine()->getTermDatabase()->getSkolemizedBody( n[0] );
NodeBuilder<> nb(kind::OR);
nb << n[0] << body.notNode();
Node lem = nb;
- Debug("quantifiers-sk") << "Skolemize lemma : " << lem << std::endl;
+ Trace("quantifiers-sk") << "Skolemize lemma : " << lem << std::endl;
d_out->lemma( lem );
d_skolemized[n] = true;
}
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index cab94fb5c..39063942d 100644
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -28,8 +28,6 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::inst;
-//#define NESTED_PATTERN_SELECTION
-
/** trigger class constructor */
Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) :
d_quantEngine( qe ), d_f( f ){
@@ -46,7 +44,7 @@ d_quantEngine( qe ), d_f( f ){
d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] );
}else{
d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes[0], qe );
- d_mg->setActiveAdd();
+ d_mg->setActiveAdd(true);
}
}else{
d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption );
@@ -55,7 +53,7 @@ d_quantEngine( qe ), d_f( f ){
}
}else{
d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe );
- d_mg->setActiveAdd();
+ d_mg->setActiveAdd(true);
}
if( d_nodes.size()==1 ){
if( isSimpleTrigger( d_nodes[0] ) ){
@@ -75,6 +73,7 @@ d_quantEngine( qe ), d_f( f ){
qe->getTermDatabase()->registerTrigger( this, d_nodes[i].getOperator() );
}
}
+ Trace("trigger-debug") << "Finished making trigger." << std::endl;
}
void Trigger::resetInstantiationRound(){
@@ -126,7 +125,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
qe->getTermDatabase()->computeVarContains( temp[i] );
for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ temp[i] ].size(); j++ ){
Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j];
- if( v.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(v)==f ){
if( vars.find( v )==vars.end() ){
varCount++;
vars[ v ] = true;
@@ -146,6 +145,12 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
}
}
if( varCount<f[0].getNumChildren() ){
+ Trace("trigger-debug") << "Don't consider trigger since it does not contain all variables in " << f << std::endl;
+ for( unsigned i=0; i<nodes.size(); i++) {
+ Trace("trigger-debug") << nodes[i] << " ";
+ }
+ Trace("trigger-debug") << std::endl;
+
//do not generate multi-trigger if it does not contain all variables
return NULL;
}else{
@@ -225,7 +230,7 @@ bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
}
bool Trigger::isUsable( Node n, Node f ){
- if( n.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n)==f ){
if( isAtomicTrigger( n ) ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
if( !isUsable( n[i], f ) ){
@@ -249,11 +254,71 @@ bool Trigger::isUsable( Node n, Node f ){
}
}
+bool nodeContainsVar( Node n, Node v ){
+ if( n==v) {
+ return true;
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++) {
+ if( nodeContainsVar(n[i], v) ){
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+Node Trigger::getIsUsableTrigger( Node n, Node f, bool pol, bool hasPol ) {
+ if( options::relationalTriggers() ){
+ if( n.getKind()==EQUAL || n.getKind()==IFF || n.getKind()==GEQ ){
+ Node rtr;
+ for( unsigned i=0; i<2; i++) {
+ unsigned j = (i==0) ? 1 : 0;
+ if( n[j].getKind()==INST_CONSTANT && isUsableTrigger(n[i], f) && !nodeContainsVar( n[i], n[j] ) ) {
+ rtr = n;
+ break;
+ }
+ }
+ if( n[0].getType().isInteger() ){
+ //try to rearrange?
+ std::map< Node, Node > m;
+ if (QuantArith::getMonomialSumLit(n, m) ){
+ for( std::map< Node, Node >::iterator it = m.begin(); it!=m.end(); ++it ){
+ if( !it->first.isNull() && it->first.getKind()==INST_CONSTANT ){
+ Node veq;
+ if( QuantArith::isolate( it->first, m, veq, n.getKind() ) ){
+ int vti = veq[0]==it->first ? 1 : 0;
+ if( isUsableTrigger(veq[vti], f) && !nodeContainsVar( veq[vti], veq[vti==0 ? 1 : 0]) ){
+ rtr = veq;
+ }
+ }
+ }
+ }
+ }
+ }
+ if( !rtr.isNull() ){
+ Trace("relational-trigger") << "Relational trigger : " << std::endl;
+ Trace("relational-trigger") << " " << rtr << " (from " << n << ")" << std::endl;
+ Trace("relational-trigger") << " in quantifier " << f << std::endl;
+ if( hasPol ){
+ Trace("relational-trigger") << " polarity : " << pol << std::endl;
+ }
+ Node rtr2 = (hasPol && pol) ? rtr.negate() : rtr;
+ return rtr2;
+ }
+ }
+ }
+ bool usable = quantifiers::TermDb::getInstConstAttr(n)==f && isAtomicTrigger( n ) && isUsable( n, f );
+ Trace("usable") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==f) << " " << isAtomicTrigger( n ) << " " << isUsable( n, f ) << std::endl;
+ if( usable ){
+ return n;
+ }else{
+ return Node::null();
+ }
+}
+
bool Trigger::isUsableTrigger( Node n, Node f ){
- //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF;
- bool usable = n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f );
- Trace("usable") << n << " usable : " << usable << std::endl;
- return usable;
+ Node nu = getIsUsableTrigger(n,f);
+ return !nu.isNull();
}
bool Trigger::isAtomicTrigger( Node n ){
@@ -263,7 +328,7 @@ bool Trigger::isAtomicTrigger( Node n ){
bool Trigger::isSimpleTrigger( Node n ){
if( isAtomicTrigger( n ) ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(n[i]) ){
return false;
}
}
@@ -274,55 +339,51 @@ bool Trigger::isSimpleTrigger( Node n ){
}
-bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){
+bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ){
if( patMap.find( n )==patMap.end() ){
patMap[ n ] = false;
+ bool newHasPol = (n.getKind()==IFF || n.getKind()==XOR) ? false : hasPol;
+ bool newPol = n.getKind()==NOT ? !pol : pol;
if( tstrt==TS_MIN_TRIGGER ){
if( n.getKind()==FORALL ){
-#ifdef NESTED_PATTERN_SELECTION
- //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt );
- return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt );
-#else
return false;
-#endif
}else{
bool retVal = false;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
+ bool newPol2 = (n.getKind()==IMPLIES && i==0) ? !newPol : newPol;
+ bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol2, newHasPol2 ) ){
retVal = true;
}
}
if( retVal ){
return true;
- }else if( isUsableTrigger( n, f ) ){
- patMap[ n ] = true;
- return true;
}else{
- return false;
+ Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ if( !nu.isNull() ){
+ patMap[ nu ] = true;
+ return true;
+ }else{
+ return false;
+ }
}
}
}else{
bool retVal = false;
- if( isUsableTrigger( n, f ) ){
- patMap[ n ] = true;
+ Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ if( !nu.isNull() ){
+ patMap[ nu ] = true;
if( tstrt==TS_MAX_TRIGGER ){
return true;
}else{
retVal = true;
}
}
- if( n.getKind()==FORALL ){
-#ifdef NESTED_PATTERN_SELECTION
- //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){
- // retVal = true;
- //}
- if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){
- retVal = true;
- }
-#endif
- }else{
+ if( n.getKind()!=FORALL ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
+ bool newPol2 = (n.getKind()==IMPLIES && i==0) ? !newPol : newPol;
+ bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol2, newHasPol2 ) ){
retVal = true;
}
}
@@ -367,7 +428,7 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto
}
}
}
- collectPatTerms2( qe, f, n, patMap, tstrt );
+ collectPatTerms2( qe, f, n, patMap, tstrt, true, true );
for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){
if( it->second ){
patTerms.push_back( it->first );
@@ -380,9 +441,9 @@ bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeff
Assert( coeffs.empty() );
NodeBuilder<> t(kind::PLUS);
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
if( n[i].getKind()==INST_CONSTANT ){
- if( n[i].getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
coeffs[ n[i] ] = Node::null();
}else{
coeffs.clear();
@@ -405,13 +466,13 @@ bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeff
}
return true;
}else if( n.getKind()==MULT ){
- if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){
- if( !n[1].hasAttribute(InstConstantAttribute()) ){
+ if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){
+ if( !quantifiers::TermDb::hasInstConstAttr(n[1]) ){
coeffs[ n[0] ] = n[1];
return true;
}
- }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){
- if( !n[0].hasAttribute(InstConstantAttribute()) ){
+ }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
+ if( !quantifiers::TermDb::hasInstConstAttr(n[0]) ){
coeffs[ n[1] ] = n[0];
return true;
}
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index ca9124751..28fb2acda 100644
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -92,8 +92,9 @@ public:
private:
/** is subterm of trigger usable */
static bool isUsable( Node n, Node f );
+ static Node getIsUsableTrigger( Node n, Node f, bool pol = true, bool hasPol = false );
/** collect all APPLY_UF pattern terms for f in n */
- static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt );
+ static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol );
public:
//different strategies for choosing trigger terms
enum {
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 0bb0f1f79..0fe50aad6 100644..100755
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -27,6 +27,9 @@
#include "theory/quantifiers/trigger.h"
#include "theory/rewriterules/efficient_e_matching.h"
#include "theory/rewriterules/rr_trigger.h"
+#include "theory/quantifiers/bounded_integers.h"
+#include "theory/quantifiers/rewrite_engine.h"
+#include "theory/uf/options.h"
using namespace std;
using namespace CVC4;
@@ -47,7 +50,11 @@ d_lemmas_produced_c(u){
d_hasAddedLemma = false;
//the model object
- d_model = new quantifiers::FirstOrderModel( c, "FirstOrderModel" );
+ if( options::fmfFullModelCheck() ){
+ d_model = new quantifiers::fmcheck::FirstOrderModelFmc( this, c, "FirstOrderModelFmc" );
+ }else{
+ d_model = new quantifiers::FirstOrderModelIG( c, "FirstOrderModelIG" );
+ }
//add quantifiers modules
if( !options::finiteModelFind() || options::fmfInstEngine() ){
@@ -57,11 +64,24 @@ d_lemmas_produced_c(u){
}else{
d_inst_engine = NULL;
}
- if( options::finiteModelFind() ){
+ if( options::finiteModelFind() ){
d_model_engine = new quantifiers::ModelEngine( c, this );
d_modules.push_back( d_model_engine );
+ if( options::fmfBoundInt() ){
+ d_bint = new quantifiers::BoundedIntegers( c, this );
+ d_modules.push_back( d_bint );
+ }else{
+ d_bint = NULL;
+ }
}else{
d_model_engine = NULL;
+ d_bint = NULL;
+ }
+ if( options::rewriteRulesAsAxioms() ){
+ d_rr_engine = new quantifiers::RewriteEngine( c, this );
+ d_modules.push_back(d_rr_engine);
+ }else{
+ d_rr_engine = NULL;
}
//options
@@ -251,7 +271,6 @@ void QuantifiersEngine::computeTermVector( Node f, InstMatch& m, std::vector< No
bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms ){
Assert( f.getKind()==FORALL );
- Assert( !f.hasAttribute(InstConstantAttribute()) );
Assert( vars.size()==terms.size() );
Node body = getInstantiation( f, vars, terms );
//make the lemma
@@ -266,7 +285,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
Trace("inst") << "*** Instantiate " << f << " with " << std::endl;
uint64_t maxInstLevel = 0;
for( int i=0; i<(int)terms.size(); i++ ){
- if( terms[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(terms[i]) ){
Debug("inst")<< "***& Bad Instantiate " << f << " with " << std::endl;
for( int i=0; i<(int)terms.size(); i++ ){
Debug("inst") << " " << terms[i] << std::endl;
@@ -432,8 +451,6 @@ bool QuantifiersEngine::addSplit( Node n, bool reqPhase, bool reqPhasePol ){
}
bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool reqPhasePol ){
- //Assert( !n1.hasAttribute(InstConstantAttribute()) );
- //Assert( !n2.hasAttribute(InstConstantAttribute()) );
//Assert( !areEqual( n1, n2 ) );
//Assert( !areDisequal( n1, n2 ) );
Kind knd = n1.getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
@@ -463,7 +480,6 @@ void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){
if( d_phase_reqs[f]->isPhaseReq( nodes[i] ) ){
bool preq = d_phase_reqs[f]->getPhaseReq( nodes[i] );
nodes[i] = NodeManager::currentNM()->mkNode( IFF, nodes[i], NodeManager::currentNM()->mkConst<bool>(preq) );
- d_term_db->setInstantiationConstantAttr( nodes[i], f );
nodeChanged = true;
}
//else if( qe->isPhaseReqEquality( f, trNodes[i] ) ){
@@ -617,35 +633,48 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f,
}else{
int sortId = 0;
if( optInternalRepSortInference() ){
+ //if( options::ufssSymBreak() ){
sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( f, f[0][index] );
}
if( d_int_rep[sortId].find( r )==d_int_rep[sortId].end() ){
- std::vector< Node > eqc;
- getEquivalenceClass( r, eqc );
//find best selection for representative
Node r_best;
- int r_best_score = -1;
- for( size_t i=0; i<eqc.size(); i++ ){
- int score = getRepScore( eqc[i], f, index );
- if( optInternalRepSortInference() ){
- int e_sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( eqc[i]);
- if( score>=0 && e_sortId!=sortId ){
- score += 100;
- }
+ if( options::fmfRelevantDomain() ){
+ Trace("internal-rep-debug") << "Consult relevant domain to mkRep " << r << std::endl;
+ r_best = d_qe->getModelEngine()->getRelevantDomain()->getRelevantTerm( f, index, r );
+ Trace("internal-rep-debug") << "Returned " << r_best << " " << r << std::endl;
+ }else{
+ std::vector< Node > eqc;
+ getEquivalenceClass( r, eqc );
+ int r_best_score = -1;
+ for( size_t i=0; i<eqc.size(); i++ ){
+ int score = getRepScore( eqc[i], f, index );
+ if( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(eqc[i]) ){
+ if( optInternalRepSortInference() ){
+ int e_sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( eqc[i]);
+ if( score>=0 && e_sortId!=sortId ){
+ score += 100;
+ }
+ }
+ //score prefers earliest use of this term as a representative
+ if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){
+ r_best = eqc[i];
+ r_best_score = score;
+ }
+ }
}
- //score prefers earliest use of this term as a representative
- if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){
- r_best = eqc[i];
- r_best_score = score;
+ if( r_best.isNull() ){
+ Node ic = d_qe->getTermDatabase()->getInstantiationConstant( f, index );
+ r_best = d_qe->getTermDatabase()->getFreeVariableForInstConstant( ic );
+ }
+ //now, make sure that no other member of the class is an instance
+ if( !optInternalRepSortInference() ){
+ r_best = getInstance( r_best, eqc );
+ }
+ //store that this representative was chosen at this point
+ if( d_rep_score.find( r_best )==d_rep_score.end() ){
+ d_rep_score[ r_best ] = d_reset_count;
}
- }
- //now, make sure that no other member of the class is an instance
- if( !optInternalRepSortInference() ){
- r_best = getInstance( r_best, eqc );
- }
- //store that this representative was chosen at this point
- if( d_rep_score.find( r_best )==d_rep_score.end() ){
- d_rep_score[ r_best ] = d_reset_count;
}
d_int_rep[sortId][r] = r_best;
if( r_best!=a ){
@@ -723,4 +752,4 @@ int EqualityQueryQuantifiersEngine::getRepScore( Node n, Node f, int index ){
bool EqualityQueryQuantifiersEngine::optInternalRepSortInference() {
return false; //shown to be not effective
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index bfa19bb98..b075f7be8 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -56,14 +56,17 @@ public:
virtual void assertNode( Node n ) = 0;
virtual void propagate( Theory::Effort level ){}
virtual Node getNextDecisionRequest() { return TNode::null(); }
- virtual Node explain(TNode n) = 0;
+ virtual Node explain(TNode n) { return TNode::null(); }
};/* class QuantifiersModule */
namespace quantifiers {
- class InstantiationEngine;
- class ModelEngine;
class TermDb;
class FirstOrderModel;
+ //modules
+ class InstantiationEngine;
+ class ModelEngine;
+ class BoundedIntegers;
+ class RewriteEngine;
}/* CVC4::theory::quantifiers */
namespace inst {
@@ -80,6 +83,7 @@ class EqualityQueryQuantifiersEngine;
class QuantifiersEngine {
friend class quantifiers::InstantiationEngine;
friend class quantifiers::ModelEngine;
+ friend class quantifiers::RewriteEngine;
friend class inst::InstMatch;
private:
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
@@ -87,10 +91,6 @@ private:
TheoryEngine* d_te;
/** vector of modules for quantifiers */
std::vector< QuantifiersModule* > d_modules;
- /** instantiation engine */
- quantifiers::InstantiationEngine* d_inst_engine;
- /** model engine */
- quantifiers::ModelEngine* d_model_engine;
/** equality query class */
EqualityQueryQuantifiersEngine* d_eq_query;
/** for computing relevance of quantifiers */
@@ -99,6 +99,14 @@ private:
std::map< Node, QuantPhaseReq* > d_phase_reqs;
/** efficient e-matcher */
EfficientEMatcher* d_eem;
+ /** instantiation engine */
+ quantifiers::InstantiationEngine* d_inst_engine;
+ /** model engine */
+ quantifiers::ModelEngine* d_model_engine;
+ /** bounded integers utility */
+ quantifiers::BoundedIntegers * d_bint;
+ /** rewrite rules utility */
+ quantifiers::RewriteEngine * d_rr_engine;
private:
/** list of all quantifiers seen */
std::vector< Node > d_quants;
@@ -155,6 +163,8 @@ public:
void getPhaseReqTerms( Node f, std::vector< Node >& nodes );
/** get efficient e-matching utility */
EfficientEMatcher* getEfficientEMatcher() { return d_eem; }
+ /** get bounded integers utility */
+ quantifiers::BoundedIntegers * getBoundedIntegers() { return d_bint; }
public:
/** initialize */
void finishInit();
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index f6da32bbf..800e007f7 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -14,6 +14,7 @@
#include "theory/rep_set.h"
#include "theory/type_enumerator.h"
+#include "theory/quantifiers/bounded_integers.h"
using namespace std;
using namespace CVC4;
@@ -94,26 +95,38 @@ void RepSet::toStream(std::ostream& out){
}
-RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){
+RepSetIterator::RepSetIterator( QuantifiersEngine * qe, RepSet* rs ) : d_qe(qe), d_rep_set( rs ){
d_incomplete = false;
+}
+int RepSetIterator::domainSize( int i ) {
+ Assert(i>=0);
+ if( d_enum_type[i]==ENUM_DOMAIN_ELEMENTS ){
+ return d_domain[i].size();
+ }else{
+ return d_domain[i][0];
+ }
}
bool RepSetIterator::setQuantifier( Node f ){
+ Trace("rsi") << "Make rsi for " << f << std::endl;
Assert( d_types.empty() );
//store indicies
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
d_types.push_back( f[0][i].getType() );
}
+ d_owner = f;
return initialize();
}
bool RepSetIterator::setFunctionDomain( Node op ){
+ Trace("rsi") << "Make rsi for " << op << std::endl;
Assert( d_types.empty() );
TypeNode tn = op.getType();
for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
d_types.push_back( tn[i] );
}
+ d_owner = op;
return initialize();
}
@@ -132,22 +145,80 @@ bool RepSetIterator::initialize(){
Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
d_rep_set->add( var );
}
- }else if( tn.isInteger() || tn.isReal() ){
- Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl;
- d_incomplete = true;
- //enumerate if the sort is reasonably small, the upper bound of 128 is chosen arbitrarily for now
- }else if( tn.getCardinality().isFinite() && tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=128 ){
+ }else if( tn.isInteger() ){
+ bool inc = false;
+ //check if it is bound
+ if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
+ if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){
+ Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded integer." << std::endl;
+ d_enum_type.push_back( ENUM_RANGE );
+ }else{
+ inc = true;
+ }
+ }else{
+ inc = true;
+ }
+ if( inc ){
+ //check if it is otherwise bound
+ if( d_bounds[0].find(i)!=d_bounds[0].end() && d_bounds[1].find(i)!=d_bounds[1].end() ){
+ Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded." << std::endl;
+ d_enum_type.push_back( ENUM_RANGE );
+ }else{
+ Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl;
+ d_incomplete = true;
+ }
+ }
+ //enumerate if the sort is reasonably small, the upper bound of 1000 is chosen arbitrarily for now
+ }else if( tn.getCardinality().isFinite() && tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=1000 ){
d_rep_set->complete( tn );
}else{
- Trace("fmf-incomplete") << "Incomplete because of unknown type " << tn << std::endl;
+ Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
d_incomplete = true;
}
- if( d_rep_set->hasType( tn ) ){
- for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
- d_domain[i].push_back( j );
+ if( d_enum_type.size()<=i ){
+ d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS );
+ if( d_rep_set->hasType( tn ) ){
+ for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
+ d_domain[i].push_back( j );
+ }
+ }else{
+ return false;
}
- }else{
- return false;
+ }
+ }
+ //must set a variable index order based on bounded integers
+ if (d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers()) {
+ Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
+ std::vector< int > varOrder;
+ for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars(d_owner); i++ ){
+ varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i));
+ }
+ for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
+ if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
+ varOrder.push_back(i);
+ }
+ }
+ Trace("bound-int-rsi") << "Variable order : ";
+ for( unsigned i=0; i<varOrder.size(); i++) {
+ Trace("bound-int-rsi") << varOrder[i] << " ";
+ }
+ Trace("bound-int-rsi") << std::endl;
+ std::vector< int > indexOrder;
+ indexOrder.resize(varOrder.size());
+ for( unsigned i=0; i<varOrder.size(); i++){
+ indexOrder[varOrder[i]] = i;
+ }
+ Trace("bound-int-rsi") << "Will use index order : ";
+ for( unsigned i=0; i<indexOrder.size(); i++) {
+ Trace("bound-int-rsi") << indexOrder[i] << " ";
+ }
+ Trace("bound-int-rsi") << std::endl;
+ setIndexOrder(indexOrder);
+ }
+ //now reset the indices
+ for (unsigned i=0; i<d_index.size(); i++) {
+ if (!resetIndex(i, true)){
+ break;
}
}
return true;
@@ -161,7 +232,7 @@ void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
d_var_order[d_index_order[i]] = i;
}
}
-
+/*
void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
d_domain.clear();
d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );
@@ -172,29 +243,104 @@ void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
}
}
}
+*/
+bool RepSetIterator::resetIndex( int i, bool initial ) {
+ d_index[i] = 0;
+ int ii = d_index_order[i];
+ Trace("bound-int-rsi") << "Reset " << i << " " << ii << " " << initial << std::endl;
+ //determine the current range
+ if( d_enum_type[ii]==ENUM_RANGE ){
+ if( initial || ( d_qe->getBoundedIntegers() && !d_qe->getBoundedIntegers()->isGroundRange( d_owner, d_owner[0][ii] ) ) ){
+ Trace("bound-int-rsi") << "Getting range of " << d_owner[0][ii] << std::endl;
+ Node l, u;
+ if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
+ d_qe->getBoundedIntegers()->getBoundValues( d_owner, d_owner[0][ii], this, l, u );
+ }
+ for( unsigned b=0; b<2; b++ ){
+ if( d_bounds[b].find(ii)!=d_bounds[b].end() ){
+ Trace("bound-int-rsi") << "May further limit bound(" << b << ") based on " << d_bounds[b][ii] << std::endl;
+ if( b==0 && (l.isNull() || d_bounds[b][ii].getConst<Rational>() > l.getConst<Rational>()) ){
+ l = d_bounds[b][ii];
+ }else if( b==1 && (u.isNull() || d_bounds[b][ii].getConst<Rational>() <= u.getConst<Rational>()) ){
+ u = NodeManager::currentNM()->mkNode( MINUS, d_bounds[b][ii],
+ NodeManager::currentNM()->mkConst( Rational(1) ) );
+ u = Rewriter::rewrite( u );
+ }
+ }
+ }
+
+ if( l.isNull() || u.isNull() ){
+ //failed, abort the iterator
+ d_index.clear();
+ return false;
+ }else{
+ Trace("bound-int-rsi") << "Can limit bounds of " << d_owner[0][ii] << " to " << l << "..." << u << std::endl;
+ Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
+ Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
+ d_domain[ii].clear();
+ Node tl = l;
+ Node tu = u;
+ if( d_qe->getBoundedIntegers() && d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][ii] ) ){
+ d_qe->getBoundedIntegers()->getBounds( d_owner, d_owner[0][ii], this, tl, tu );
+ }
+ d_lower_bounds[ii] = tl;
+ if( ra==NodeManager::currentNM()->mkConst(true) ){
+ long rr = range.getConst<Rational>().getNumerator().getLong()+1;
+ Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl;
+ d_domain[ii].push_back( (int)rr );
+ }else{
+ Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << d_owner[0][ii] << "." << std::endl;
+ d_incomplete = true;
+ d_domain[ii].push_back( 0 );
+ }
+ }
+ }else{
+ Trace("bound-int-rsi") << d_owner[0][ii] << " has ground range, skip." << std::endl;
+ }
+ }
+ return true;
+}
-void RepSetIterator::increment2( int counter ){
+int RepSetIterator::increment2( int counter ){
Assert( !isFinished() );
#ifdef DISABLE_EVAL_SKIP_MULTIPLE
counter = (int)d_index.size()-1;
#endif
//increment d_index
- while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){
+ if( counter>=0){
+ Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
+ }
+ while( counter>=0 && d_index[counter]>=(int)(domainSize(counter)-1) ){
counter--;
+ if( counter>=0){
+ Trace("rsi-debug") << "domain size of " << counter << " is " << domainSize(counter) << std::endl;
+ }
}
if( counter==-1 ){
d_index.clear();
}else{
+ d_index[counter]++;
+ bool emptyDomain = false;
for( int i=(int)d_index.size()-1; i>counter; i-- ){
- d_index[i] = 0;
+ if (!resetIndex(i)){
+ break;
+ }else if( domainSize(i)<=0 ){
+ emptyDomain = true;
+ }
+ }
+ if( emptyDomain ){
+ Trace("rsi-debug") << "This is an empty domain, increment again." << std::endl;
+ return increment();
}
- d_index[counter]++;
}
+ return counter;
}
-void RepSetIterator::increment(){
+int RepSetIterator::increment(){
if( !isFinished() ){
- increment2( (int)d_index.size()-1 );
+ return increment2( (int)d_index.size()-1 );
+ }else{
+ return -1;
}
}
@@ -203,10 +349,18 @@ bool RepSetIterator::isFinished(){
}
Node RepSetIterator::getTerm( int i ){
- TypeNode tn = d_types[d_index_order[i]];
- Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
int index = d_index_order[i];
- return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
+ if( d_enum_type[index]==ENUM_DOMAIN_ELEMENTS ){
+ TypeNode tn = d_types[index];
+ Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );
+ return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];
+ }else{
+ Trace("rsi-debug") << index << " " << d_lower_bounds[index] << " " << d_index[index] << std::endl;
+ Node t = NodeManager::currentNM()->mkNode(PLUS, d_lower_bounds[index],
+ NodeManager::currentNM()->mkConst( Rational(d_index[index]) ) );
+ t = Rewriter::rewrite( t );
+ return t;
+ }
}
void RepSetIterator::debugPrint( const char* c ){
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
index 24fa7473e..a619915ee 100644
--- a/src/theory/rep_set.h
+++ b/src/theory/rep_set.h
@@ -23,6 +23,8 @@
namespace CVC4 {
namespace theory {
+class QuantifiersEngine;
+
/** this class stores a representative set */
class RepSet {
public:
@@ -52,11 +54,27 @@ typedef std::vector< int > RepDomain;
/** this class iterates over a RepSet */
class RepSetIterator {
+public:
+ enum {
+ ENUM_DOMAIN_ELEMENTS,
+ ENUM_RANGE,
+ };
private:
+ QuantifiersEngine * d_qe;
//initialize function
bool initialize();
+ //for enum ranges
+ std::map< int, Node > d_lower_bounds;
+ //domain size
+ int domainSize( int i );
+ //node this is rep set iterator is for
+ Node d_owner;
+ //reset index
+ bool resetIndex( int i, bool initial = false );
+ /** set index order */
+ void setIndexOrder( std::vector< int >& indexOrder );
public:
- RepSetIterator( RepSet* rs );
+ RepSetIterator( QuantifiersEngine * qe, RepSet* rs );
~RepSetIterator(){}
//set that this iterator will be iterating over instantiations for a quantifier
bool setQuantifier( Node f );
@@ -65,6 +83,8 @@ public:
public:
//pointer to model
RepSet* d_rep_set;
+ //enumeration type?
+ std::vector< int > d_enum_type;
//index we are considering
std::vector< int > d_index;
//types we are considering
@@ -86,15 +106,13 @@ public:
// for example, if d_index_order = { 2, 0, 1 }
// then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
std::map< int, int > d_var_order;
+ //intervals
+ std::map< int, Node > d_bounds[2];
public:
- /** set index order */
- void setIndexOrder( std::vector< int >& indexOrder );
- /** set domain */
- void setDomain( std::vector< RepDomain >& domain );
/** increment the iterator at index=counter */
- void increment2( int counter );
+ int increment2( int counter );
/** increment the iterator */
- void increment();
+ int increment();
/** is the iterator finished? */
bool isFinished();
/** get the i_th term we are considering */
diff --git a/src/theory/rewriterules/rr_inst_match.cpp b/src/theory/rewriterules/rr_inst_match.cpp
index a4c111f86..4908e5ec0 100644
--- a/src/theory/rewriterules/rr_inst_match.cpp
+++ b/src/theory/rewriterules/rr_inst_match.cpp
@@ -137,14 +137,13 @@ class DumbPatMatcher: public PatMatcher{
/* The order of the matching is:
reset arg1, nextMatch arg1, reset arg2, nextMatch arg2, ... */
ApplyMatcher::ApplyMatcher( Node pat, QuantifiersEngine* qe): d_pattern(pat){
- // Assert( pat.hasAttribute(InstConstantAttribute()) );
//set-up d_variables, d_constants, d_childrens
for( size_t i=0; i< d_pattern.getNumChildren(); ++i ){
//EqualityQuery* q = qe->getEqualityQuery(d_pattern[i].getType());
EqualityQuery* q = qe->getEqualityQuery();
Assert( q != NULL );
- if( d_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(d_pattern[i]) ){
if( d_pattern[i].getKind()==INST_CONSTANT ){
//It's a variable
d_variables.push_back(make_triple((TNode)d_pattern[i],i,q));
@@ -172,7 +171,7 @@ bool ApplyMatcher::reset(TNode t, InstMatch & m, QuantifiersEngine* qe){
//if t is null
Assert( !t.isNull() );
- Assert( !t.hasAttribute(InstConstantAttribute()) );
+ Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
Assert( t.getKind()==d_pattern.getKind() );
Assert( (t.getKind()!=APPLY_UF && t.getKind()!=APPLY_CONSTRUCTOR)
|| t.getOperator()==d_pattern.getOperator() );
@@ -411,7 +410,7 @@ public:
size_t numFreeVar(TNode t){
size_t n = 0;
for( size_t i=0, size =t.getNumChildren(); i < size; ++i ){
- if( t[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(t[i]) ){
if( t[i].getKind()==INST_CONSTANT ){
//variable
++n;
@@ -958,7 +957,7 @@ Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){
/** TODO: something simpler to see if the pattern is a good
arithmetic pattern */
std::map< Node, Node > d_arith_coeffs;
- if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){
+ if( !Trigger::getPatternArithmetic( quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) ){
Message() << "(?) Unknown matching pattern is " << pat << std::endl;
Unimplemented("pattern not implemented");
return new DumbMatcher();
@@ -983,17 +982,17 @@ Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){
PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
Debug("inst-match-gen") << "Pattern term is " << pat << std::endl;
- Assert( pat.hasAttribute(InstConstantAttribute()) );
+ Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
if( pat.getKind()==kind::NOT && pat[0].getKind() == kind::EQUAL){
/* Difference */
return new UfDeqMatcher(pat, qe);
} else if (pat.getKind() == kind::EQUAL){
- if( !pat[0].hasAttribute(InstConstantAttribute() )){
- Assert(pat[1].hasAttribute(InstConstantAttribute()));
+ if( !quantifiers::TermDb::hasInstConstAttr(pat[0])){
+ Assert(quantifiers::TermDb::hasInstConstAttr(pat[1]));
return new UfCstEqMatcher(pat[1], pat[0], qe);
- }else if( !pat[1].hasAttribute(InstConstantAttribute() )){
- Assert(pat[0].hasAttribute(InstConstantAttribute()));
+ }else if( !quantifiers::TermDb::hasInstConstAttr(pat[1] )){
+ Assert(quantifiers::TermDb::hasInstConstAttr(pat[0]));
return new UfCstEqMatcher(pat[0], pat[1], qe);
}else{
std::vector< Node > pats(pat.begin(),pat.end());
@@ -1009,7 +1008,7 @@ PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
/** TODO: something simpler to see if the pattern is a good
arithmetic pattern */
std::map< Node, Node > d_arith_coeffs;
- if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){
+ if( !Trigger::getPatternArithmetic( quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) ){
Debug("inst-match-gen") << "(?) Unknown matching pattern is " << pat << std::endl;
Message() << "(?) Unknown matching pattern is " << pat << std::endl;
return new DumbPatMatcher();
@@ -1033,7 +1032,7 @@ PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
ArithMatcher::ArithMatcher(Node pat, QuantifiersEngine* qe): d_pattern(pat){
- if(Trigger::getPatternArithmetic(pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) )
+ if(Trigger::getPatternArithmetic(quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) )
{
Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_pattern << std::endl;
Assert(false);
diff --git a/src/theory/rewriterules/rr_inst_match.h b/src/theory/rewriterules/rr_inst_match.h
index 3ec9438fd..aa89430c1 100644
--- a/src/theory/rewriterules/rr_inst_match.h
+++ b/src/theory/rewriterules/rr_inst_match.h
@@ -67,7 +67,7 @@ public:
/** legal candidate */
static inline bool isLegalCandidate( TNode n ){
return !n.getAttribute(NoMatchAttribute()) &&
- ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute())) &&
+ ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n)) &&
( !options::efficientEMatching() || n.hasAttribute(AvailableInTermDb()) );
}
diff --git a/src/theory/rewriterules/rr_trigger.cpp b/src/theory/rewriterules/rr_trigger.cpp
index 7e35be7ad..13250cf1b 100644
--- a/src/theory/rewriterules/rr_trigger.cpp
+++ b/src/theory/rewriterules/rr_trigger.cpp
@@ -65,7 +65,7 @@ bool Trigger::getNextMatch(){
int Trigger::addInstantiations( InstMatch& baseMatch ){
int addedLemmas = d_mg->addInstantiations( baseMatch,
- d_nodes[0].getAttribute(InstConstantAttribute()),
+ quantifiers::TermDb::getInstConstAttr(d_nodes[0]),
d_quantEngine);
if( addedLemmas>0 ){
Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was ";
@@ -91,7 +91,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
qe->getTermDatabase()->computeVarContains( temp[i] );
for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ temp[i] ].size(); j++ ){
Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j];
- if( v.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(v)==f ){
if( vars.find( v )==vars.end() ){
vars[ v ] = true;
foundVar = true;
@@ -181,7 +181,7 @@ bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
}
bool Trigger::isUsable( Node n, Node f ){
- if( n.getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n)==f ){
if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){
std::map< Node, Node > coeffs;
return getPatternArithmetic( f, n, coeffs );
@@ -201,7 +201,7 @@ bool Trigger::isUsable( Node n, Node f ){
bool Trigger::isSimpleTrigger( Node n ){
if( isAtomicTrigger( n ) ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(n[i]) ){
return false;
}
}
@@ -318,9 +318,9 @@ bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coef
Assert( coeffs.empty() );
NodeBuilder<> t(kind::PLUS);
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].hasAttribute(InstConstantAttribute()) ){
+ if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
if( n[i].getKind()==INST_CONSTANT ){
- if( n[i].getAttribute(InstConstantAttribute())==f ){
+ if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
coeffs[ n[i] ] = Node::null();
}else{
coeffs.clear();
@@ -343,12 +343,12 @@ bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coef
}
return true;
}else if( n.getKind()==MULT ){
- if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){
- Assert( !n[1].hasAttribute(InstConstantAttribute()) );
+ if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){
+ Assert( !quantifiers::TermDb::hasInstConstAttr(n[1]) );
coeffs[ n[0] ] = n[1];
return true;
- }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){
- Assert( !n[0].hasAttribute(InstConstantAttribute()) );
+ }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
+ Assert( !quantifiers::TermDb::hasInstConstAttr(n[0]) );
coeffs[ n[1] ] = n[0];
return true;
}
diff --git a/src/theory/rewriterules/rr_trigger.h b/src/theory/rewriterules/rr_trigger.h
index f1a37d937..f02f38d0e 100644
--- a/src/theory/rewriterules/rr_trigger.h
+++ b/src/theory/rewriterules/rr_trigger.h
@@ -94,8 +94,7 @@ public:
public:
/** is usable trigger */
static inline bool isUsableTrigger( TNode n, TNode f ){
- //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF;
- return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f );
+ return quantifiers::TermDb::getInstConstAttr(n)==f && isAtomicTrigger( n ) && isUsable( n, f );
}
static inline bool isAtomicTrigger( TNode n ){
return
diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h
index 19cb3e987..a542214b2 100644
--- a/src/theory/rewriterules/theory_rewriterules.h
+++ b/src/theory/rewriterules/theory_rewriterules.h
@@ -263,7 +263,7 @@ private:
rewriter::Subst & vars);
//create inst variable
- std::vector<Node> createInstVariable( std::vector<Node> & vars );
+ std::vector<Node> createInstVariable( Node r, std::vector<Node> & vars );
/** statistics class */
class Statistics {
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp
index 589556802..7e1d42bb2 100644
--- a/src/theory/rewriterules/theory_rewriterules_rules.cpp
+++ b/src/theory/rewriterules/theory_rewriterules_rules.cpp
@@ -151,7 +151,7 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
vars.push_back(*v);
};
/* Instantiation version */
- std::vector<Node> inst_constants = createInstVariable(vars);
+ std::vector<Node> inst_constants = createInstVariable(r,vars);
/* Body/Remove_term/Guards/Triggers */
Node body = r[2][1];
TNode new_terms = r[2][1];
@@ -232,7 +232,11 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
NodeBuilder<> patternListB(kind::INST_PATTERN_LIST);
patternListB << static_cast<Node>(patternB);
forallB << static_cast<Node>(patternListB);
- getOutputChannel().lemma((Node) forallB);
+ Node lem = (Node) forallB;
+ lem = Rewriter::rewrite(lem);
+ QRewriteRuleAttribute qra;
+ lem.setAttribute(qra,r);
+ getOutputChannel().lemma(lem);
return;
}
@@ -376,7 +380,7 @@ bool TheoryRewriteRules::addRewritePattern(TNode pattern, TNode body,
}
-std::vector<Node> TheoryRewriteRules::createInstVariable( std::vector<Node> & vars ){
+std::vector<Node> TheoryRewriteRules::createInstVariable( Node r, std::vector<Node> & vars ){
std::vector<Node> inst_constant;
inst_constant.reserve(vars.size());
for( std::vector<Node>::const_iterator v = vars.begin();
@@ -384,6 +388,11 @@ std::vector<Node> TheoryRewriteRules::createInstVariable( std::vector<Node> & va
//make instantiation constants
Node ic = NodeManager::currentNM()->mkInstConstant( (*v).getType() );
inst_constant.push_back( ic );
+ InstConstantAttribute ica;
+ ic.setAttribute(ica,r);
+ //also set the no-match attribute
+ NoMatchAttribute nma;
+ ic.setAttribute(nma,true);
};
return inst_constant;
}
diff --git a/src/theory/rewriterules/theory_rewriterules_type_rules.h b/src/theory/rewriterules/theory_rewriterules_type_rules.h
index 256957855..fa6bb2227 100644
--- a/src/theory/rewriterules/theory_rewriterules_type_rules.h
+++ b/src/theory/rewriterules/theory_rewriterules_type_rules.h
@@ -33,6 +33,8 @@ public:
* Compute the type for (and optionally typecheck) a term belonging
* to the theory of rewriterules.
*
+ * @param nodeManager the NodeManager in use
+ * @param n the node to compute the type of
* @param check if true, the node's type should be checked as well
* as computed.
*/
diff --git a/src/theory/shared_terms_database.cpp b/src/theory/shared_terms_database.cpp
index 58b8cf697..3a767b5c3 100644
--- a/src/theory/shared_terms_database.cpp
+++ b/src/theory/shared_terms_database.cpp
@@ -131,9 +131,9 @@ bool SharedTermsDatabase::propagateSharedEquality(TheoryId theory, TNode a, TNod
// Propagate away
Node equality = a.eqNode(b);
if (value) {
- d_theoryEngine->assertToTheory(equality, theory, THEORY_BUILTIN);
+ d_theoryEngine->assertToTheory(equality, equality, theory, THEORY_BUILTIN);
} else {
- d_theoryEngine->assertToTheory(equality.notNode(), theory, THEORY_BUILTIN);
+ d_theoryEngine->assertToTheory(equality.notNode(), equality.notNode(), theory, THEORY_BUILTIN);
}
// As you were
diff --git a/src/theory/strings/Makefile b/src/theory/strings/Makefile
new file mode 100644
index 000000000..e92c24ab7
--- /dev/null
+++ b/src/theory/strings/Makefile
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/theory/strings
+
+include $(topdir)/Makefile.subdir
diff --git a/src/theory/strings/Makefile.am b/src/theory/strings/Makefile.am
new file mode 100644
index 000000000..38efa33f3
--- /dev/null
+++ b/src/theory/strings/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -D__BUILDING_CVC4LIB \
+ -I@srcdir@/../../include -I@srcdir@/../.. -I@builddir@/../..
+AM_CXXFLAGS = -Wall $(FLAG_VISIBILITY_HIDDEN)
+
+noinst_LTLIBRARIES = libstrings.la
+
+libstrings_la_SOURCES = \
+ theory_strings.h \
+ theory_strings.cpp \
+ theory_strings_rewriter.h \
+ theory_strings_rewriter.cpp \
+ theory_strings_type_rules.h \
+ type_enumerator.h \
+ theory_strings_preprocess.h \
+ theory_strings_preprocess.cpp
+
+EXTRA_DIST = \
+ kinds
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
new file mode 100644
index 000000000..814276a7c
--- /dev/null
+++ b/src/theory/strings/kinds
@@ -0,0 +1,105 @@
+# kinds [for strings theory]
+#
+
+theory THEORY_STRINGS ::CVC4::theory::strings::TheoryStrings "theory/strings/theory_strings.h"
+
+properties check parametric propagate
+
+rewriter ::CVC4::theory::strings::TheoryStringsRewriter "theory/strings/theory_strings_rewriter.h"
+
+typechecker "theory/strings/theory_strings_type_rules.h"
+
+
+operator STRING_CONCAT 2: "string concat"
+
+operator STRING_IN_REGEXP 2 "membership"
+
+operator STRING_LENGTH 1 "string length"
+
+#sort CHAR_TYPE \
+# Cardinality::INTEGERS \
+# well-founded \
+# "NodeManager::currentNM()->mkConst(::CVC4::String())" \
+# "util/regexp.h" \
+# "String type"
+
+sort STRING_TYPE \
+ Cardinality::INTEGERS \
+ well-founded \
+ "NodeManager::currentNM()->mkConst(::CVC4::String())" \
+ "util/regexp.h" \
+ "String type"
+
+sort REGEXP_TYPE \
+ Cardinality::INTEGERS \
+ well-founded \
+ "NodeManager::currentNM()->mkConst(::CVC4::RegExp())" \
+ "util/regexp.h" \
+ "RegExp type"
+
+enumerator STRING_TYPE \
+ "::CVC4::theory::strings::StringEnumerator" \
+ "theory/strings/type_enumerator.h"
+
+#enumerator REGEXP_TYPE \
+# "::CVC4::theory::strings::RegExpEnumerator" \
+# "theory/strings/type_enumerator.h"
+
+constant CONST_STRING \
+ ::CVC4::String \
+ ::CVC4::strings::StringHashFunction \
+ "util/regexp.h" \
+ "a string of characters"
+
+constant CONST_REGEXP \
+ ::CVC4::RegExp \
+ ::CVC4::RegExpHashFunction \
+ "util/regexp.h" \
+ "a regular expression"
+
+typerule CONST_STRING ::CVC4::theory::strings::StringConstantTypeRule
+typerule CONST_REGEXP ::CVC4::theory::strings::RegExpConstantTypeRule
+
+# equal equal / less than / output
+operator STRING_TO_REGEXP 1 "convert string to regexp"
+operator REGEXP_CONCAT 2: "regexp concat"
+operator REGEXP_OR 2: "regexp or"
+operator REGEXP_INTER 2: "regexp intersection"
+operator REGEXP_STAR 1 "regexp *"
+operator REGEXP_PLUS 1 "regexp +"
+operator REGEXP_OPT 1 "regexp ?"
+
+#constant REGEXP_EMPTY \
+# ::CVC4::RegExp \
+# ::CVC4::RegExpHashFunction \
+# "util/string.h" \
+# "a regexp contains nothing"
+
+#constant REGEXP_ALL \
+# ::CVC4::RegExp \
+# ::CVC4::RegExpHashFunction \
+# "util/string.h" \
+# "a regexp contains all strings"
+
+#constant REGEXP_SIGMA \
+# ::CVC4::RegExp \
+# ::CVC4::RegExpHashFunction \
+# "util/string.h" \
+# "a regexp contains an arbitrary charactor"
+
+typerule REGEXP_CONCAT ::CVC4::theory::strings::RegExpConcatTypeRule
+typerule REGEXP_OR ::CVC4::theory::strings::RegExpOrTypeRule
+typerule REGEXP_INTER ::CVC4::theory::strings::RegExpInterTypeRule
+typerule REGEXP_STAR ::CVC4::theory::strings::RegExpStarTypeRule
+typerule REGEXP_PLUS ::CVC4::theory::strings::RegExpPlusTypeRule
+typerule REGEXP_OPT ::CVC4::theory::strings::RegExpOptTypeRule
+
+typerule STRING_TO_REGEXP ::CVC4::theory::strings::StringToRegExpTypeRule
+
+
+typerule STRING_CONCAT ::CVC4::theory::strings::StringConcatTypeRule
+typerule STRING_LENGTH ::CVC4::theory::strings::StringLengthTypeRule
+
+typerule STRING_IN_REGEXP ::CVC4::theory::strings::StringInRegExpTypeRule
+
+endtheory
diff --git a/src/theory/strings/options b/src/theory/strings/options
new file mode 100644
index 000000000..9226f9999
--- /dev/null
+++ b/src/theory/strings/options
@@ -0,0 +1,11 @@
+#
+# Option specification file for CVC4
+# See src/options/base_options for a description of this file format
+#
+
+module STRINGS "theory/strings/options.h" Strings theory
+
+option stringCharCardinality str-alphabet-card --str-alphabet-card=N int16_t :default 256 :read-write
+ the cardinality of the characters used by the theory of string, default 256
+
+endmodule
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
new file mode 100644
index 000000000..7d5edd0f7
--- /dev/null
+++ b/src/theory/strings/theory_strings.cpp
@@ -0,0 +1,1711 @@
+/********************* */
+/*! \file theory_strings.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: Tianyi Liang, Andrew Reynolds
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of the theory of strings.
+ **
+ ** Implementation of the theory of strings.
+ **/
+
+
+#include "theory/strings/theory_strings.h"
+#include "theory/valuation.h"
+#include "expr/kind.h"
+#include "theory/rewriter.h"
+#include "expr/command.h"
+#include "theory/model.h"
+#include "smt/logic_exception.h"
+#include "theory/strings/options.h"
+#include "theory/strings/type_enumerator.h"
+#include <cmath>
+
+#define STR_UNROLL_INDUCTION
+
+using namespace std;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe)
+ : Theory(THEORY_STRINGS, c, u, out, valuation, logicInfo, qe),
+ d_notify( *this ),
+ d_equalityEngine(d_notify, c, "theory::strings::TheoryStrings"),
+ d_conflict( c, false ),
+ d_infer(c),
+ d_infer_exp(c),
+ d_nf_pairs(c),
+ d_ind_map1(c),
+ d_ind_map2(c),
+ d_ind_map_exp(c),
+ d_ind_map_lemma(c),
+ //d_lit_to_decide_index( c, 0 ),
+ //d_lit_to_decide( c ),
+ d_lit_to_unroll( c )
+{
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
+ d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
+ d_equalityEngine.addFunctionKind(kind::STRING_CONCAT);
+
+ d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
+ d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+ d_true = NodeManager::currentNM()->mkConst( true );
+ d_false = NodeManager::currentNM()->mkConst( false );
+}
+
+TheoryStrings::~TheoryStrings() {
+
+}
+
+Node TheoryStrings::getRepresentative( Node t ) {
+ if( d_equalityEngine.hasTerm( t ) ){
+ return d_equalityEngine.getRepresentative( t );
+ }else{
+ return t;
+ }
+}
+
+bool TheoryStrings::hasTerm( Node a ){
+ return d_equalityEngine.hasTerm( a );
+}
+
+bool TheoryStrings::areEqual( Node a, Node b ){
+ if( a==b ){
+ return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areEqual( a, b );
+ }else{
+ return false;
+ }
+}
+
+bool TheoryStrings::areDisequal( Node a, Node b ){
+ if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areDisequal( a, b, false );
+ }else{
+ return false;
+ }
+}
+
+Node TheoryStrings::getLength( Node t ) {
+ EqcInfo * ei = getOrMakeEqcInfo( t );
+ Node length_term = ei->d_length_term;
+ if( length_term.isNull()) {
+ //typically shouldnt be necessary
+ length_term = t;
+ }
+ return NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, length_term );
+}
+
+void TheoryStrings::setMasterEqualityEngine(eq::EqualityEngine* eq) {
+ d_equalityEngine.setMasterEqualityEngine(eq);
+}
+
+void TheoryStrings::addSharedTerm(TNode t) {
+ Debug("strings") << "TheoryStrings::addSharedTerm(): "
+ << t << " " << t.getType().isBoolean() << endl;
+ d_equalityEngine.addTriggerTerm(t, THEORY_STRINGS);
+ Debug("strings") << "TheoryStrings::addSharedTerm() finished" << std::endl;
+}
+
+EqualityStatus TheoryStrings::getEqualityStatus(TNode a, TNode b) {
+ if( d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b) ){
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+ if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ }
+ return EQUALITY_UNKNOWN;
+}
+
+void TheoryStrings::propagate(Effort e)
+{
+ // direct propagation now
+}
+
+bool TheoryStrings::propagate(TNode literal) {
+ Debug("strings-propagate") << "TheoryStrings::propagate(" << literal << ")" << std::endl;
+ // If already in conflict, no more propagation
+ if (d_conflict) {
+ Debug("strings-propagate") << "TheoryStrings::propagate(" << literal << "): already in conflict" << std::endl;
+ return false;
+ }
+ Trace("strings-prop") << "strPropagate " << literal << std::endl;
+ // Propagate out
+ bool ok = d_out->propagate(literal);
+ if (!ok) {
+ d_conflict = true;
+ }
+ return ok;
+}
+
+/** explain */
+void TheoryStrings::explain(TNode literal, std::vector<TNode>& assumptions){
+ Debug("strings-explain") << "Explain " << literal << std::endl;
+ bool polarity = literal.getKind() != kind::NOT;
+ TNode atom = polarity ? literal : literal[0];
+ if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
+ d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ } else {
+ d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ }
+}
+
+Node TheoryStrings::explain( TNode literal ){
+ std::vector< TNode > assumptions;
+ explain( literal, assumptions );
+ if( assumptions.empty() ){
+ return d_true;
+ }else if( assumptions.size()==1 ){
+ return assumptions[0];
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::AND, assumptions );
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// MODEL GENERATION
+/////////////////////////////////////////////////////////////////////////////
+
+
+void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
+ Trace("strings-model") << "TheoryStrings : Collect model info, fullModel = " << fullModel << std::endl;
+ Trace("strings-model") << "TheoryStrings : assertEqualityEngine." << std::endl;
+ m->assertEqualityEngine( &d_equalityEngine );
+ // Generate model
+ std::vector< Node > nodes;
+ getEquivalenceClasses( nodes );
+ std::map< Node, Node > processed;
+ std::vector< std::vector< Node > > col;
+ std::vector< Node > lts;
+ seperateByLength( nodes, col, lts );
+ //step 1 : get all values for known lengths
+ std::vector< Node > lts_values;
+ //std::map< Node, bool > values_used;
+ for( unsigned i=0; i<col.size(); i++ ){
+ Trace("strings-model") << "Checking length for " << col[i][0] << " (length is " << lts[i] << ")" << std::endl;
+ if( lts[i].isConst() ){
+ lts_values.push_back( lts[i] );
+ //values_used[ lts[i] ] = true;
+ }else{
+ //get value for lts[i];
+ if( !lts[i].isNull() ){
+ Node v = d_valuation.getModelValue(lts[i]);
+ //Node v = m->getValue(lts[i]);
+ Trace("strings-model") << "Model value for " << lts[i] << " is " << v << std::endl;
+ lts_values.push_back( v );
+ //values_used[ v ] = true;
+ }else{
+ Trace("strings-model-warn") << "No length for eqc " << col[i][0] << std::endl;
+ Assert( false );
+ lts_values.push_back( Node::null() );
+ }
+ }
+ }
+ ////step 2 : assign arbitrary values for unknown lengths?
+ //for( unsigned i=0; i<col.size(); i++ ){
+ // if(
+ //}
+ Trace("strings-model") << "Assign to equivalence classes..." << std::endl;
+ //step 3 : assign values to equivalence classes that are pure variables
+ for( unsigned i=0; i<col.size(); i++ ){
+ std::vector< Node > pure_eq;
+ Trace("strings-model") << "The equivalence classes ";
+ for( unsigned j=0; j<col[i].size(); j++ ) {
+ Trace("strings-model") << col[i][j] << " ";
+ //check if col[i][j] has only variables
+ EqcInfo* ei = getOrMakeEqcInfo( col[i][j], false );
+ Node cst = ei ? ei->d_const_term : Node::null();
+ if( cst.isNull() ){
+ Assert( d_normal_forms.find( col[i][j] )!=d_normal_forms.end() );
+ if( d_normal_forms[col[i][j]].size()==1 ){//&& d_normal_forms[col[i][j]][0]==col[i][j] ){
+ pure_eq.push_back( col[i][j] );
+ }
+ }else{
+ processed[col[i][j]] = cst;
+ }
+ }
+ Trace("strings-model") << "have length " << lts_values[i] << std::endl;
+
+ Trace("strings-model") << "Need to assign values of length " << lts_values[i] << " to equivalence classes ";
+ for( unsigned j=0; j<pure_eq.size(); j++ ){
+ Trace("strings-model") << pure_eq[j] << " ";
+ }
+ Trace("strings-model") << std::endl;
+
+ //use type enumerator
+ StringEnumeratorLength sel(lts_values[i].getConst<Rational>().getNumerator().toUnsignedInt());
+ for( unsigned j=0; j<pure_eq.size(); j++ ){
+ Assert( !sel.isFinished() );
+ Node c = *sel;
+ while( d_equalityEngine.hasTerm( c ) ){
+ ++sel;
+ Assert( !sel.isFinished() );
+ c = *sel;
+ }
+ ++sel;
+ Trace("strings-model") << "*** Assigned constant " << c << " for " << pure_eq[j] << std::endl;
+ processed[pure_eq[j]] = c;
+ m->assertEquality( pure_eq[j], c, true );
+ }
+ }
+ Trace("strings-model") << "String Model : Finished." << std::endl;
+ //step 4 : assign constants to all other equivalence classes
+ for( unsigned i=0; i<nodes.size(); i++ ){
+ if( processed.find( nodes[i] )==processed.end() ){
+ Assert( d_normal_forms.find( nodes[i] )!=d_normal_forms.end() );
+ Trace("strings-model") << "Construct model for " << nodes[i] << " based on normal form ";
+ for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
+ if( j>0 ) Trace("strings-model") << " ++ ";
+ Trace("strings-model") << d_normal_forms[nodes[i]][j];
+ Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
+ if( !r.isConst() && processed.find( r )==processed.end() ){
+ Trace("strings-model") << "(UNPROCESSED)";
+ }
+ }
+ Trace("strings-model") << std::endl;
+ std::vector< Node > nc;
+ for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
+ Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
+ Assert( r.isConst() || processed.find( r )!=processed.end() );
+ nc.push_back(r.isConst() ? r : processed[r]);
+ }
+ Node cc = mkConcat( nc );
+ Assert( cc.getKind()==kind::CONST_STRING );
+ Trace("strings-model") << "*** Determined constant " << cc << " for " << nodes[i] << std::endl;
+ processed[nodes[i]] = cc;
+ m->assertEquality( nodes[i], cc, true );
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// MAIN SOLVER
+/////////////////////////////////////////////////////////////////////////////
+
+void TheoryStrings::preRegisterTerm(TNode n) {
+ Debug("strings-prereg") << "TheoryStrings::preRegisterTerm() " << n << endl;
+ //collectTerms( n );
+ switch (n.getKind()) {
+ case kind::EQUAL:
+ d_equalityEngine.addTriggerEquality(n);
+ break;
+ case kind::STRING_IN_REGEXP:
+ d_equalityEngine.addTriggerPredicate(n);
+ break;
+ default:
+ if(n.getKind() == kind::VARIABLE || n.getKind()==kind::SKOLEM) {
+ if( std::find( d_length_intro_vars.begin(), d_length_intro_vars.end(), n )==d_length_intro_vars.end() ){
+ Node n_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n);
+ Node n_len_geq_zero = NodeManager::currentNM()->mkNode( kind::GEQ, n_len, d_zero);
+ Trace("strings-lemma") << "Strings: Add lemma " << n_len_geq_zero << std::endl;
+ d_out->lemma(n_len_geq_zero);
+ }
+ }
+ if (n.getType().isBoolean()) {
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine.addTriggerPredicate(n);
+ } else {
+ // Function applications/predicates
+ d_equalityEngine.addTerm(n);
+ }
+ break;
+ }
+}
+
+void TheoryStrings::check(Effort e) {
+ bool polarity;
+ TNode atom;
+
+ if( !done() && !hasTerm( d_emptyString ) ){
+ preRegisterTerm( d_emptyString );
+ }
+
+ // Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
+ Trace("strings-check") << "Theory of strings, check : " << e << std::endl;
+ while ( !done() && !d_conflict)
+ {
+ // Get all the assertions
+ Assertion assertion = get();
+ TNode fact = assertion.assertion;
+
+ Trace("strings-assertion") << "get assertion: " << fact << endl;
+
+ polarity = fact.getKind() != kind::NOT;
+ atom = polarity ? fact : fact[0];
+ if (atom.getKind() == kind::EQUAL) {
+ d_equalityEngine.assertEquality(atom, polarity, fact);
+ } else {
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ }
+#ifdef STR_UNROLL_INDUCTION
+ //check if it is a literal to unroll?
+ if( d_lit_to_unroll.find( atom )!=d_lit_to_unroll.end() ){
+ Trace("strings-ind") << "Strings-ind : Possibly unroll for : " << atom << ", polarity = " << polarity << std::endl;
+ }
+#endif
+ }
+ doPendingFacts();
+
+
+ bool addedLemma = false;
+ if( e == EFFORT_FULL && !d_conflict ) {
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ //if eqc.getType is string
+ if (eqc.getType().isString()) {
+ //EqcInfo* ei = getOrMakeEqcInfo( eqc, true );
+ //get the constant for the equivalence class
+ //int c_len = ...;
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Node n = (*eqc_i);
+
+ //if n is concat, and
+ //if n has not instantiatied the concat..length axiom
+ //then, add lemma
+ if( n.getKind() == kind::STRING_CONCAT || n.getKind() == kind::CONST_STRING ){
+ if( d_length_inst.find(n)==d_length_inst.end() ){
+ d_length_inst[n] = true;
+ Trace("strings-debug") << "get n: " << n << endl;
+ Node sk = NodeManager::currentNM()->mkSkolem( "lsym_$$", n.getType(), "created for concat lemma" );
+ d_length_intro_vars.push_back( sk );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, n );
+ eq = Rewriter::rewrite(eq);
+ Trace("strings-lemma") << "Strings: Add lemma " << eq << std::endl;
+ d_out->lemma(eq);
+ Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
+ Node lsum;
+ if( n.getKind() == kind::STRING_CONCAT ){
+ //add lemma
+ std::vector<Node> node_vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node lni = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[i] );
+ node_vec.push_back(lni);
+ }
+ lsum = NodeManager::currentNM()->mkNode( kind::PLUS, node_vec );
+ }else{
+ //add lemma
+ lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
+ }
+ Node ceq = NodeManager::currentNM()->mkNode( kind::EQUAL, skl, lsum );
+ ceq = Rewriter::rewrite(ceq);
+ Trace("strings-lemma") << "Strings: Add lemma " << ceq << std::endl;
+ d_out->lemma(ceq);
+ addedLemma = true;
+ }
+ }
+ ++eqc_i;
+ }
+ }
+ ++eqcs_i;
+ }
+ if( !addedLemma ){
+ addedLemma = checkNormalForms();
+ Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ){
+ addedLemma = checkInductiveEquations();
+ Trace("strings-process") << "Done check inductive equations, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ }
+ }
+ }
+ Trace("strings-process") << "Theory of strings, done check : " << e << std::endl;
+}
+
+TheoryStrings::EqcInfo::EqcInfo( context::Context* c ) : d_const_term(c), d_length_term(c), d_cardinality_lem_k(c) {
+
+}
+
+TheoryStrings::EqcInfo * TheoryStrings::getOrMakeEqcInfo( Node eqc, bool doMake ) {
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( eqc );
+ if( eqc_i==d_eqc_info.end() ){
+ if( doMake ){
+ EqcInfo* ei = new EqcInfo( getSatContext() );
+ d_eqc_info[eqc] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+ }else{
+ return (*eqc_i).second;
+ }
+}
+
+
+/** Conflict when merging two constants */
+void TheoryStrings::conflict(TNode a, TNode b){
+ Node conflictNode;
+ if (a.getKind() == kind::CONST_BOOLEAN) {
+ conflictNode = explain( a.iffNode(b) );
+ } else {
+ conflictNode = explain( a.eqNode(b) );
+ }
+ Debug("strings-conflict") << "CONFLICT: Eq engine conflict : " << conflictNode << std::endl;
+ d_out->conflict( conflictNode );
+ d_conflict = true;
+}
+
+/** called when a new equivalance class is created */
+void TheoryStrings::eqNotifyNewClass(TNode t){
+ if( t.getKind() == kind::CONST_STRING ){
+ EqcInfo * ei =getOrMakeEqcInfo( t, true );
+ ei->d_const_term = t;
+ }
+ if( t.getKind() == kind::STRING_LENGTH ){
+ Trace("strings-debug") << "New length eqc : " << t << std::endl;
+ Node r = d_equalityEngine.getRepresentative(t[0]);
+ EqcInfo * ei = getOrMakeEqcInfo( r, true );
+ ei->d_length_term = t[0];
+ }
+}
+
+/** called when two equivalance classes will merge */
+void TheoryStrings::eqNotifyPreMerge(TNode t1, TNode t2){
+ EqcInfo * e2 = getOrMakeEqcInfo(t2, false);
+ if( e2 ){
+ EqcInfo * e1 = getOrMakeEqcInfo( t1 );
+ //add information from e2 to e1
+ if( !e2->d_const_term.get().isNull() ){
+ e1->d_const_term.set( e2->d_const_term );
+ }
+ if( !e2->d_length_term.get().isNull() ){
+ e1->d_length_term.set( e2->d_length_term );
+ }
+ if( e2->d_cardinality_lem_k.get()>e1->d_cardinality_lem_k.get() ) {
+ e1->d_cardinality_lem_k.set( e2->d_cardinality_lem_k );
+ }
+ }
+ if( hasTerm( d_zero ) ){
+ Node leqc;
+ if( areEqual(d_zero, t1) ){
+ leqc = t2;
+ }else if( areEqual(d_zero, t2) ){
+ leqc = t1;
+ }
+ if( !leqc.isNull() ){
+ //scan equivalence class to see if we apply
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( leqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Node n = (*eqc_i);
+ if( n.getKind()==kind::STRING_LENGTH ){
+ if( !hasTerm( d_emptyString ) || !areEqual(n[0], d_emptyString ) ){
+ //apply the rule length(n[0])==0 => n[0] == ""
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, n[0], d_emptyString );
+ d_pending.push_back( eq );
+ Node eq_exp = NodeManager::currentNM()->mkNode( kind::EQUAL, n, d_zero );
+ d_pending_exp[eq] = eq_exp;
+ Trace("strings-infer") << "Strings : Infer " << eq << " from " << eq_exp << std::endl;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ }
+ }
+ ++eqc_i;
+ }
+ }
+ }
+}
+
+/** called when two equivalance classes have merged */
+void TheoryStrings::eqNotifyPostMerge(TNode t1, TNode t2) {
+
+}
+
+/** called when two equivalance classes are disequal */
+void TheoryStrings::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+
+}
+
+void TheoryStrings::computeCareGraph(){
+ Theory::computeCareGraph();
+}
+
+void TheoryStrings::doPendingFacts() {
+ int i=0;
+ while( !d_conflict && i<(int)d_pending.size() ){
+ Node fact = d_pending[i];
+ Node exp = d_pending_exp[ fact ];
+ Trace("strings-pending") << "Process pending fact : " << fact << " from " << exp << std::endl;
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ if (atom.getKind() == kind::EQUAL) {
+ Assert( d_equalityEngine.hasTerm( atom[0] ) );
+ Assert( d_equalityEngine.hasTerm( atom[1] ) );
+ d_equalityEngine.assertEquality( atom, polarity, exp );
+ }else{
+ d_equalityEngine.assertPredicate( atom, polarity, exp );
+ }
+ i++;
+ }
+ d_pending.clear();
+ d_pending_exp.clear();
+}
+void TheoryStrings::doPendingLemmas() {
+ if( !d_conflict && !d_lemma_cache.empty() ){
+ for( unsigned i=0; i<d_lemma_cache.size(); i++ ){
+ Trace("strings-pending") << "Process pending lemma : " << d_lemma_cache[i] << std::endl;
+ d_out->lemma( d_lemma_cache[i] );
+ }
+ for( std::map< Node, bool >::iterator it = d_pending_req_phase.begin(); it != d_pending_req_phase.end(); ++it ){
+ Trace("strings-pending") << "Require phase : " << it->first << ", polarity = " << it->second << std::endl;
+ d_out->requirePhase( it->first, it->second );
+ }
+ d_lemma_cache.clear();
+ d_pending_req_phase.clear();
+ }
+}
+
+void TheoryStrings::getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
+ std::vector< std::vector< Node > > &normal_forms, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< Node > &normal_form_src) {
+ // EqcItr
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ) {
+ Node n = (*eqc_i);
+ Trace("strings-process") << "Process term " << n << std::endl;
+ if( n.getKind() == kind::CONST_STRING || n.getKind() == kind::STRING_CONCAT ) {
+ std::vector<Node> nf_n;
+ std::vector<Node> nf_exp_n;
+ if( n.getKind() == kind::CONST_STRING ){
+ if( n!=d_emptyString ) {
+ nf_n.push_back( n );
+ }
+ } else if( n.getKind() == kind::STRING_CONCAT ) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node nr = d_equalityEngine.getRepresentative( n[i] );
+ std::vector< Node > nf_temp;
+ std::vector< Node > nf_exp_temp;
+ Trace("strings-process") << "Normalizing subterm " << n[i] << " = " << nr << std::endl;
+ normalizeEquivalenceClass( nr, visited, nf_temp, nf_exp_temp );
+ if( d_conflict || !d_pending.empty() || !d_lemma_cache.empty() ) {
+ return;
+ }
+ if( nf.size()!=1 || nf[0]!=d_emptyString ) {
+ for( unsigned r=0; r<nf_temp.size(); r++ ) {
+ Assert( nf_temp[r].getKind()!=kind::STRING_CONCAT );
+ }
+ nf_n.insert( nf_n.end(), nf_temp.begin(), nf_temp.end() );
+ }
+ nf_exp_n.insert( nf_exp_n.end(), nf_exp_temp.begin(), nf_exp_temp.end() );
+ if( nr!=n[i] ) {
+ nf_exp_n.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n[i], nr ) );
+ }
+ }
+ }
+ normal_forms.push_back(nf_n);
+ normal_forms_exp.push_back(nf_exp_n);
+ normal_form_src.push_back(n);
+ }
+ /* should we add these?
+ else {
+ //var/sk?
+ std::vector<Node> nf_n;
+ std::vector<Node> nf_exp_n;
+ nf_n.push_back(n);
+ normal_forms.push_back(nf_n);
+ normal_forms_exp.push_back(nf_exp_n);
+ normal_form_src.push_back(n);
+ }*/
+ ++eqc_i;
+ }
+
+ // Test the result
+ if( !normal_forms.empty() ) {
+ Trace("strings-solve") << "--- Normal forms for equivlance class " << eqc << " : " << std::endl;
+ for( unsigned i=0; i<normal_forms.size(); i++ ) {
+ Trace("strings-solve") << "#" << i << " (from " << normal_form_src[i] << ") : ";
+ for( unsigned j=0; j<normal_forms[i].size(); j++ ) {
+ if(j>0) Trace("strings-solve") << ", ";
+ Trace("strings-solve") << normal_forms[i][j];
+ }
+ Trace("strings-solve") << std::endl;
+ Trace("strings-solve") << " Explanation is : ";
+ if(normal_forms_exp[i].size() == 0) {
+ Trace("strings-solve") << "NONE";
+ } else {
+ for( unsigned j=0; j<normal_forms_exp[i].size(); j++ ) {
+ if(j>0) Trace("strings-solve") << " AND ";
+ Trace("strings-solve") << normal_forms_exp[i][j];
+ }
+ }
+ Trace("strings-solve") << std::endl;
+ }
+ }
+}
+//nf_exp is conjunction
+void TheoryStrings::normalizeEquivalenceClass( Node eqc, std::vector< Node > & visited, std::vector< Node > & nf, std::vector< Node > & nf_exp ) {
+ Trace("strings-process") << "Process equivalence class " << eqc << std::endl;
+ if( std::find( visited.begin(), visited.end(), eqc )!=visited.end() ){
+ //nf.push_back( eqc );
+ if( eqc.getKind()==kind::STRING_CONCAT ){
+ for( unsigned i=0; i<eqc.getNumChildren(); i++ ){
+ if( !d_equalityEngine.hasTerm(d_emptyString) || !d_equalityEngine.areEqual( eqc[i], d_emptyString ) ){
+ nf.push_back( eqc[i] );
+ }
+ }
+ }else if( !d_equalityEngine.hasTerm(d_emptyString) || !d_equalityEngine.areEqual( eqc, d_emptyString ) ){
+ nf.push_back( eqc );
+ }
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : already visited." << std::endl;
+ } else if (d_equalityEngine.hasTerm(d_emptyString) && d_equalityEngine.areEqual( eqc, d_emptyString )){
+ //do nothing
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : empty." << std::endl;
+ d_normal_forms[eqc].clear();
+ d_normal_forms_exp[eqc].clear();
+ } else {
+ visited.push_back( eqc );
+ if(d_normal_forms.find(eqc)==d_normal_forms.end() ){
+ //phi => t = s1 * ... * sn
+ // normal form for each non-variable term in this eqc (s1...sn)
+ std::vector< std::vector< Node > > normal_forms;
+ // explanation for each normal form (phi)
+ std::vector< std::vector< Node > > normal_forms_exp;
+ // record terms for each normal form (t)
+ std::vector< Node > normal_form_src;
+ //Get Normal Forms
+ getNormalForms(eqc, visited, nf, normal_forms, normal_forms_exp, normal_form_src);
+ if( d_conflict || !d_pending.empty() || !d_lemma_cache.empty() ) {
+ return;
+ }
+
+ unsigned i = 0;
+ //unify each normal form > 0 with normal_forms[0]
+ for( unsigned j=1; j<normal_forms.size(); j++ ) {
+
+ Trace("strings-solve") << "Process normal form #0 against #" << j << "..." << std::endl;
+ if( isNormalFormPair( normal_form_src[i], normal_form_src[j] ) ){
+ Trace("strings-solve") << "Already normalized (in cache)." << std::endl;
+ }else{
+ Trace("strings-solve") << "Not in cache." << std::endl;
+ //the current explanation for why the prefix is equal
+ std::vector< Node > curr_exp;
+ curr_exp.insert(curr_exp.end(), normal_forms_exp[i].begin(), normal_forms_exp[i].end() );
+ curr_exp.insert(curr_exp.end(), normal_forms_exp[j].begin(), normal_forms_exp[j].end() );
+ curr_exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, normal_form_src[i], normal_form_src[j] ) );
+ //ensure that normal_forms[i] and normal_forms[j] are the same modulo equality
+ unsigned index_i = 0;
+ unsigned index_j = 0;
+ bool success;
+ do
+ {
+ success = false;
+ //if we are at the end
+ if(index_i==normal_forms[i].size() || index_j==normal_forms[j].size() ) {
+ if( index_i==normal_forms[i].size() && index_j==normal_forms[j].size() ){
+ //we're done
+ addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ }else{
+ //the remainder must be empty
+ unsigned k = index_i==normal_forms[i].size() ? j : i;
+ unsigned index_k = index_i==normal_forms[i].size() ? index_j : index_i;
+ while(!d_conflict && index_k<normal_forms[k].size()) {
+ //can infer that this string must be empty
+ Node eq_exp;
+ if( curr_exp.empty() ) {
+ eq_exp = d_true;
+ } else if( curr_exp.size() == 1 ) {
+ eq_exp = curr_exp[0];
+ } else {
+ eq_exp = NodeManager::currentNM()->mkNode( kind::AND, curr_exp );
+ }
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, d_emptyString, normal_forms[k][index_k] );
+ Trace("strings-lemma") << "Strings : Infer " << eq << " from " << eq_exp << std::endl;
+ Assert( !d_equalityEngine.areEqual( d_emptyString, normal_forms[k][index_k] ) );
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ index_k++;
+ }
+ }
+ }else {
+ Trace("strings-solve-debug") << "Process " << normal_forms[i][index_i] << " ... " << normal_forms[j][index_j] << std::endl;
+ if(areEqual(normal_forms[i][index_i],normal_forms[j][index_j])){
+ Trace("strings-solve-debug") << "Case 1 : strings are equal" << std::endl;
+ //terms are equal, continue
+ if( normal_forms[i][index_i]!=normal_forms[j][index_j] ){
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL,normal_forms[i][index_i],
+ normal_forms[j][index_j]);
+ Trace("strings-solve-debug") << "Add to explanation : " << eq << std::endl;
+ curr_exp.push_back(eq);
+ }
+ index_j++;
+ index_i++;
+ success = true;
+ }else{
+ Node length_term_i = getLength( normal_forms[i][index_i] );
+ Node length_term_j = getLength( normal_forms[j][index_j] );
+ //check if length(normal_forms[i][index]) == length(normal_forms[j][index])
+ if( areEqual(length_term_i, length_term_j) ){
+ Trace("strings-solve-debug") << "Case 2 : string lengths are equal" << std::endl;
+ //length terms are equal, merge equivalence classes if not already done so
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[i][index_i], normal_forms[j][index_j] );
+ std::vector< Node > temp_exp;
+ temp_exp.insert(temp_exp.end(), curr_exp.begin(), curr_exp.end() );
+ temp_exp.push_back(NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ));
+ Node eq_exp = temp_exp.empty() ? d_true :
+ temp_exp.size() == 1 ? temp_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, temp_exp );
+ Trace("strings-lemma") << "Strings : Infer " << eq << " from " << eq_exp << std::endl;
+ //d_equalityEngine.assertEquality( eq, true, eq_exp );
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ return;
+ }else if( ( normal_forms[i][index_i].getKind()!=kind::CONST_STRING && index_i==normal_forms[i].size()-1 ) ||
+ ( normal_forms[j][index_j].getKind()!=kind::CONST_STRING && index_j==normal_forms[j].size()-1 ) ){
+ Trace("strings-solve-debug") << "Case 3 : at endpoint" << std::endl;
+ Node conc;
+ std::vector< Node > antec;
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ std::vector< Node > antec_new_lits;
+ std::vector< Node > eqn;
+ for( unsigned r=0; r<2; r++ ){
+ int index_k = r==0 ? index_i : index_j;
+ int k = r==0 ? i : j;
+ std::vector< Node > eqnc;
+ for( unsigned index_l=index_k; index_l<normal_forms[k].size(); index_l++ ){
+ eqnc.push_back( normal_forms[k][index_l] );
+ }
+ eqn.push_back( mkConcat( eqnc ) );
+ }
+ conc = eqn[0].eqNode( eqn[1] );
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Endpoint" );
+ return;
+ }else{
+ Trace("strings-solve-debug") << "Case 4 : must compare strings" << std::endl;
+ Node conc;
+ std::vector< Node > antec;
+ std::vector< Node > antec_new_lits;
+ //check for loops
+ //Trace("strings-loop") << "Check for loops i,j = " << (index_i+1) << "/" << normal_forms[i].size() << " " << (index_j+1) << "/" << normal_forms[j].size() << std::endl;
+ int has_loop[2] = { -1, -1 };
+ for( unsigned r=0; r<2; r++ ){
+ int index = (r==0 ? index_i : index_j);
+ int other_index = (r==0 ? index_j : index_i );
+ int n_index = (r==0 ? i : j);
+ int other_n_index = (r==0 ? j : i);
+ if( normal_forms[other_n_index][other_index].getKind() != kind::CONST_STRING ) {
+ for( unsigned lp = index+1; lp<normal_forms[n_index].size(); lp++ ){
+ if( normal_forms[n_index][lp]==normal_forms[other_n_index][other_index] ){
+ has_loop[r] = lp;
+ break;
+ }
+ }
+ }
+ }
+ if( has_loop[0]!=-1 || has_loop[1]!=-1 ){
+ int loop_n_index = has_loop[0]!=-1 ? i : j;
+ int other_n_index = has_loop[0]!=-1 ? j : i;
+ int loop_index = has_loop[0]!=-1 ? has_loop[0] : has_loop[1];
+ int index = has_loop[0]!=-1 ? index_i : index_j;
+ int other_index = has_loop[0]!=-1 ? index_j : index_i;
+ Trace("strings-loop") << "Detected possible loop for " << normal_forms[loop_n_index][loop_index];
+ Trace("strings-loop") << " ... " << normal_forms[other_n_index][other_index] << std::endl;
+
+ //we have x * s1 * .... * sm = t1 * ... * tn * x * r1 * ... * rp
+ //check if
+ //t1 * ... * tn = n[loop_n_index][index]....n[loop_n_index][loop_index-1] = y * z
+ // and
+ //s1 * ... * sk = n[other_n_index][other_index+1].....n[other_n_index][k+1] = z * y
+ // for some y,z,k
+
+ Trace("strings-loop") << "Must add lemma." << std::endl;
+ //need to break
+ Node sk_y= NodeManager::currentNM()->mkSkolem( "ysym_$$", normal_forms[i][index_i].getType(), "created for loop detection split" );
+ Node sk_z= NodeManager::currentNM()->mkSkolem( "zsym_$$", normal_forms[i][index_i].getType(), "created for loop detection split" );
+
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ //require that x is non-empty
+ Node x_empty = normal_forms[loop_n_index][loop_index].eqNode( d_emptyString );
+ x_empty = Rewriter::rewrite( x_empty );
+ //if( d_equalityEngine.hasTerm( d_emptyString ) && d_equalityEngine.areDisequal( normal_forms[loop_n_index][loop_index], d_emptyString, true ) ){
+ // antec.push_back( x_empty.negate() );
+ //}else{
+ antec_new_lits.push_back( x_empty.negate() );
+ //}
+ d_pending_req_phase[ x_empty ] = true;
+
+
+ //t1 * ... * tn = y * z
+ std::vector< Node > c1c;
+ //n[loop_n_index][index]....n[loop_n_index][loop_lindex-1]
+ for( int r=index; r<=loop_index-1; r++ ) {
+ c1c.push_back( normal_forms[loop_n_index][r] );
+ }
+ Node conc1 = mkConcat( c1c );
+ conc1 = NodeManager::currentNM()->mkNode( kind::EQUAL, conc1,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk_y, sk_z ) );
+ std::vector< Node > c2c;
+ //s1 * ... * sk = n[other_n_index][other_index+1].....n[other_n_index][k+1]
+ for( int r=other_index+1; r < (int)normal_forms[other_n_index].size(); r++ ) {
+ c2c.push_back( normal_forms[other_n_index][r] );
+ }
+ Node left2 = mkConcat( c2c );
+ std::vector< Node > c3c;
+ c3c.push_back( sk_z );
+ c3c.push_back( sk_y );
+ //r1 * ... * rk = n[loop_n_index][loop_index+1]....n[loop_n_index][loop_index-1]
+ for( int r=loop_index+1; r < (int)normal_forms[loop_n_index].size(); r++ ) {
+ c3c.push_back( normal_forms[loop_n_index][r] );
+ }
+ Node conc2 = NodeManager::currentNM()->mkNode( kind::EQUAL, left2,
+ mkConcat( c3c ) );
+
+ Node sk_y_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk_y );
+ //Node sk_z_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk_z );
+ //Node len_y_eq_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_y_len, d_zero);
+ //Node len_z_eq_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_z_len, d_zero);
+ //Node len_y_eq_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_y, d_emptyString);
+ //Node zz_imp_yz = NodeManager::currentNM()->mkNode( kind::IMPLIES, len_z_eq_zero, len_y_eq_zero);
+
+ //Node z_neq_empty = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_z, d_emptyString).negate();
+ //Node len_x_gt_len_y = NodeManager::currentNM()->mkNode( kind::GT,
+ // NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, normal_forms[other_n_index][other_index]),
+ // sk_y_len );
+ Node ant = mkExplain( antec, antec_new_lits );
+ conc = NodeManager::currentNM()->mkNode( kind::AND, conc1, conc2 );//, x_eq_y_rest );// , z_neq_empty //, len_x_gt_len_y
+
+ //Node x_eq_empty = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[other_n_index][other_index], d_emptyString);
+ //conc = NodeManager::currentNM()->mkNode( kind::OR, x_eq_empty, conc );
+
+ //we will be done
+ addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ sendLemma( ant, conc, "Loop" );
+ addInductiveEquation( normal_forms[other_n_index][other_index], sk_y, sk_z, ant, "Loop Induction" );
+ return;
+ }else{
+ Trace("strings-solve-debug") << "No loops detected." << std::endl;
+ if( normal_forms[i][index_i].getKind() == kind::CONST_STRING ||
+ normal_forms[j][index_j].getKind() == kind::CONST_STRING) {
+ unsigned const_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? i : j;
+ unsigned const_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_i : index_j;
+ unsigned nconst_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? j : i;
+ unsigned nconst_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_j : index_i;
+ Node const_str = normal_forms[const_k][const_index_k];
+ Node other_str = normal_forms[nconst_k][nconst_index_k];
+ if( other_str.getKind() == kind::CONST_STRING ) {
+ unsigned len_short = const_str.getConst<String>().size() <= other_str.getConst<String>().size() ? const_str.getConst<String>().size() : other_str.getConst<String>().size();
+ if( const_str.getConst<String>().strncmp(other_str.getConst<String>(), len_short) ) {
+ //same prefix
+ //k is the index of the string that is shorter
+ int k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? i : j;
+ int index_k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_i : index_j;
+ int l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? j : i;
+ int index_l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_j : index_i;
+ Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index_l].getConst<String>().substr(len_short) );
+ Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index_l] << " into " << normal_forms[k][index_k] << ", " << remainderStr << std::endl;
+ normal_forms[l].insert( normal_forms[l].begin()+index_l + 1, remainderStr );
+ normal_forms[l][index_l] = normal_forms[k][index_k];
+ success = true;
+ } else {
+ //curr_exp is conflict
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Conflict" );
+ return;
+ }
+ } else {
+ Assert( other_str.getKind()!=kind::STRING_CONCAT );
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ Node firstChar = const_str.getConst<String>().size() == 1 ? const_str :
+ NodeManager::currentNM()->mkConst( const_str.getConst<String>().substr(0, 1) );
+ //split the string
+ Node sk = NodeManager::currentNM()->mkSkolem( "ssym_$$", normal_forms[i][index_i].getType(), "created for split" );
+
+ Node eq1 = NodeManager::currentNM()->mkNode( kind::EQUAL, other_str, d_emptyString );
+ Node eq2_m = NodeManager::currentNM()->mkNode( kind::EQUAL, other_str,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, firstChar, sk ) );
+ Node eq2 = eq2_m;//NodeManager::currentNM()->mkNode( kind::AND, eq2_m, sk_len_geq_zero );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+ Trace("strings-solve-debug") << "Break normal form constant/variable " << std::endl;
+
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Constant Split" );
+ return;
+ }
+ }else{
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+
+ Node ldeq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ).negate();
+ if( d_equalityEngine.areDisequal( length_term_i, length_term_j, true ) ){
+ antec.push_back( ldeq );
+ }else{
+ antec_new_lits.push_back(ldeq);
+ }
+ Node sk = NodeManager::currentNM()->mkSkolem( "ssym_$$", normal_forms[i][index_i].getType(), "created for split" );
+ Node eq1 = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[i][index_i],
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, normal_forms[j][index_j], sk ) );
+ Node eq2 = NodeManager::currentNM()->mkNode( kind::EQUAL, normal_forms[j][index_j],
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, normal_forms[i][index_i], sk ) );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+ // |sk| > 0
+ //Node sk_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
+ //Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::GT, sk_len, d_zero);
+ Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, d_emptyString).negate();
+ Trace("strings-lemma") << "Strings lemma : " << sk_gt_zero << std::endl;
+ //d_out->lemma(sk_gt_zero);
+ d_lemma_cache.push_back( sk_gt_zero );
+
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "Split" );
+ return;
+ }
+ }
+ }
+ }
+ }
+ }while(success);
+ }
+ }
+
+ //construct the normal form
+ if( normal_forms.empty() ){
+ Trace("strings-solve-debug2") << "construct the normal form" << std::endl;
+ nf.push_back( eqc );
+ } else {
+ Trace("strings-solve-debug2") << "just take the first normal form" << std::endl;
+ //just take the first normal form
+ nf.insert( nf.end(), normal_forms[0].begin(), normal_forms[0].end() );
+ nf_exp.insert( nf_exp.end(), normal_forms_exp[0].begin(), normal_forms_exp[0].end() );
+ if( eqc!=normal_form_src[0] ){
+ nf_exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, eqc, normal_form_src[0] ) );
+ }
+ Trace("strings-solve-debug2") << "just take the first normal form ... done" << std::endl;
+ }
+ //if( visited.empty() ){
+ //TODO : cache?
+ //}
+ d_normal_forms[eqc].insert( d_normal_forms[eqc].end(), nf.begin(), nf.end() );
+ d_normal_forms_exp[eqc].insert( d_normal_forms_exp[eqc].end(), nf_exp.begin(), nf_exp.end() );
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : returned." << std::endl;
+ }else{
+ Trace("strings-process") << "Return process equivalence class " << eqc << " : already computed." << std::endl;
+ nf.insert( nf.end(), d_normal_forms[eqc].begin(), d_normal_forms[eqc].end() );
+ nf_exp.insert( nf_exp.end(), d_normal_forms_exp[eqc].begin(), d_normal_forms_exp[eqc].end() );
+ }
+ visited.pop_back();
+ }
+}
+
+bool TheoryStrings::normalizeDisequality( Node ni, Node nj ) {
+ //Assert( areDisequal( ni, nj ) );
+ if( d_normal_forms[ni].size()>1 || d_normal_forms[nj].size()>1 ){
+ unsigned index = 0;
+ while( index<d_normal_forms[ni].size() ){
+ Node i = d_normal_forms[ni][index];
+ Node j = d_normal_forms[nj][index];
+ Trace("strings-solve-debug") << "...Processing " << i << " " << j << std::endl;
+ if( !areEqual( i, j ) ){
+ Node li = getLength( i );
+ Node lj = getLength( j );
+ if( !areEqual(li, lj) ){
+ Trace("strings-solve") << "Case 2 : add lemma " << std::endl;
+ //must add lemma
+ std::vector< Node > antec;
+ std::vector< Node > antec_new_lits;
+ antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
+ antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
+ antec.push_back( ni.eqNode( nj ).negate() );
+ antec_new_lits.push_back( li.eqNode( lj ) );
+ std::vector< Node > conc;
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "w1sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "w2sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "w3sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk4 = NodeManager::currentNM()->mkSkolem( "w4sym_$$", ni.getType(), "created for disequality normalization" );
+ Node sk5 = NodeManager::currentNM()->mkSkolem( "w5sym_$$", ni.getType(), "created for disequality normalization" );
+ Node w1w2w3 = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 );
+ Node w1w4w5 = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk4, sk5 );
+ Node s_eq_w1w2w3 = NodeManager::currentNM()->mkNode( kind::EQUAL, ni, w1w2w3 );
+ conc.push_back( s_eq_w1w2w3 );
+ Node t_eq_w1w4w5 = NodeManager::currentNM()->mkNode( kind::EQUAL, nj, w1w4w5 );
+ conc.push_back( t_eq_w1w4w5 );
+ Node w2_neq_w4 = sk2.eqNode( sk4 ).negate();
+ conc.push_back( w2_neq_w4 );
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational( 1 ) );
+ Node w2_len_one = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2), one);
+ conc.push_back( w2_len_one );
+ Node w4_len_one = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk4), one);
+ conc.push_back( w4_len_one );
+
+ //Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2),
+ // NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk4) );
+ //conc.push_back( eq );
+ sendLemma( mkExplain( antec, antec_new_lits ), NodeManager::currentNM()->mkNode( kind::AND, conc ), "Disequality Normalize" );
+ return true;
+ }else if( areDisequal( i, j ) ){
+ Trace("strings-solve") << "Case 1 : found equal length disequal sub strings " << i << " " << j << std::endl;
+ //we are done
+ return false;
+ }
+ }
+ index++;
+ }
+ Assert( false );
+ }
+ return false;
+}
+
+void TheoryStrings::addNormalFormPair( Node n1, Node n2 ) {
+ if( !isNormalFormPair( n1, n2 ) ){
+ NodeList* lst;
+ NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
+ if( nf_i == d_nf_pairs.end() ){
+ if( d_nf_pairs.find( n2 )!=d_nf_pairs.end() ){
+ addNormalFormPair( n2, n1 );
+ return;
+ }
+ lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_nf_pairs.insertDataFromContextMemory( n1, lst );
+ Trace("strings-nf") << "Create cache for " << n1 << std::endl;
+ }else{
+ lst = (*nf_i).second;
+ }
+ Trace("strings-nf") << "Add normal form pair : " << n1 << " " << n2 << std::endl;
+ lst->push_back( n2 );
+ Assert( isNormalFormPair( n1, n2 ) );
+ }else{
+ Trace("strings-nf-debug") << "Already a normal form pair " << n1 << " " << n2 << std::endl;
+ }
+
+}
+bool TheoryStrings::isNormalFormPair( Node n1, Node n2 ) {
+ //TODO: modulo equality?
+ return isNormalFormPair2( n1, n2 ) || isNormalFormPair2( n2, n1 );
+}
+bool TheoryStrings::isNormalFormPair2( Node n1, Node n2 ) {
+ //Trace("strings-debug") << "is normal form pair. " << n1 << " " << n2 << std::endl;
+ NodeList* lst;
+ NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
+ if( nf_i != d_nf_pairs.end() ){
+ lst = (*nf_i).second;
+ for( NodeList::const_iterator i = lst->begin(); i != lst->end(); ++i ) {
+ Node n = *i;
+ if( n==n2 ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool TheoryStrings::addInductiveEquation( Node x, Node y, Node z, Node exp, const char * c ) {
+ Trace("strings-solve-debug") << "add inductive equation for " << x << " = (" << y << " " << z << ")* " << y << std::endl;
+#ifdef STR_UNROLL_INDUCTION
+ Node w = NodeManager::currentNM()->mkSkolem( "wsym_$$", x.getType(), "created for induction" );
+ Node x_eq_y_w = NodeManager::currentNM()->mkNode( kind::EQUAL, x,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, y, w ) );
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, x_eq_y_w );
+ Trace("strings-lemma") << "Strings " << c << " lemma : " << lem << std::endl;
+ d_lemma_cache.push_back( lem );
+
+ //add initial induction
+ Node lit1 = w.eqNode( d_emptyString );
+ lit1 = Rewriter::rewrite( lit1 );
+ Node wp = NodeManager::currentNM()->mkSkolem( "wpsym_$$", x.getType(), "created for induction" );
+ Node lit2 = w.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, z, y, wp ) );
+ lit2 = Rewriter::rewrite( lit2 );
+ Node split_lem = NodeManager::currentNM()->mkNode( kind::OR, lit1, lit2 );
+ Trace("strings-ind") << "Strings : Lemma " << c << " for unrolling " << split_lem << std::endl;
+ Trace("strings-lemma") << "Strings : Lemma " << c << " for unrolling " << split_lem << std::endl;
+ d_lemma_cache.push_back( split_lem );
+
+ //d_lit_to_decide.push_back( lit1 );
+ d_lit_to_unroll[lit2] = true;
+ d_pending_req_phase[lit1] = true;
+ d_pending_req_phase[lit2] = false;
+
+ x = w;
+ std::vector< Node > skc;
+ skc.push_back( y );
+ skc.push_back( z );
+ y = d_emptyString;
+ z = mkConcat( skc );
+#endif
+
+ NodeListMap::iterator itr_x_y = d_ind_map1.find(x);
+ NodeList* lst1;
+ NodeList* lst2;
+ NodeList* lste;
+ NodeList* lstl;
+ if( itr_x_y == d_ind_map1.end() ) {
+ // add x->y
+ lst1 = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map1.insertDataFromContextMemory( x, lst1 );
+ // add x->z
+ lst2 = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map2.insertDataFromContextMemory( x, lst2 );
+ // add x->exp
+ lste = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map_exp.insertDataFromContextMemory( x, lste );
+ // add x->hasLemma false
+ lstl = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_ind_map_lemma.insertDataFromContextMemory( x, lstl );
+ } else {
+ //TODO: x in (yz)*y (exp) vs x in (y1 z1)*y1 (exp1)
+ lst1 = (*itr_x_y).second;
+ lst2 = (*d_ind_map2.find(x)).second;
+ lste = (*d_ind_map_exp.find(x)).second;
+ lstl = (*d_ind_map_lemma.find(x)).second;
+ Trace("strings-solve-debug") << "Already in maps " << x << " = (" << lst1 << " " << lst2 << ")* " << lst1 << std::endl;
+ Trace("strings-solve-debug") << "... with exp = " << lste << std::endl;
+ }
+ lst1->push_back( y );
+ lst2->push_back( z );
+ lste->push_back( exp );
+#ifdef STR_UNROLL_INDUCTION
+ return true;
+#else
+ return false;
+#endif
+}
+
+void TheoryStrings::sendLemma( Node ant, Node conc, const char * c ) {
+ if( conc.isNull() ){
+ d_out->conflict(ant);
+ Trace("strings-conflict") << "CONFLICT : Strings conflict : " << ant << std::endl;
+ d_conflict = true;
+ }else{
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, ant, conc );
+ Trace("strings-lemma") << "Strings " << c << " lemma : " << lem << std::endl;
+ d_lemma_cache.push_back( lem );
+ }
+}
+
+void TheoryStrings::sendSplit( Node a, Node b, const char * c ) {
+ Node eq = a.eqNode( b );
+ eq = Rewriter::rewrite( eq );
+ Node neq = NodeManager::currentNM()->mkNode( kind::NOT, eq );
+ Node lemma_or = NodeManager::currentNM()->mkNode( kind::OR, eq, neq );
+ Trace("strings-lemma") << "Strings " << c << " split lemma : " << lemma_or << std::endl;
+ d_lemma_cache.push_back(lemma_or);
+ d_pending_req_phase[eq] = true;
+}
+
+Node TheoryStrings::mkConcat( std::vector< Node >& c ) {
+ Node cc = c.size()>1 ? NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, c ) : ( c.size()==1 ? c[0] : d_emptyString );
+ return Rewriter::rewrite( cc );
+}
+
+Node TheoryStrings::mkExplain( std::vector< Node >& a, std::vector< Node >& an ) {
+ std::vector< TNode > antec_exp;
+ for( unsigned i=0; i<a.size(); i++ ){
+ Trace("strings-solve-debug") << "Ask for explanation of " << a[i] << std::endl;
+ //assert
+ if(a[i].getKind() == kind::EQUAL) {
+ //assert( hasTerm(a[i][0]) );
+ //assert( hasTerm(a[i][1]) );
+ Assert( areEqual(a[i][0], a[i][1]) );
+ } else if( a[i].getKind()==kind::NOT && a[i][0].getKind()==kind::EQUAL ){
+ Assert( hasTerm(a[i][0][0]) );
+ Assert( hasTerm(a[i][0][1]) );
+ Assert( d_equalityEngine.areDisequal(a[i][0][0], a[i][0][1], true) );
+ }
+ unsigned ps = antec_exp.size();
+ explain(a[i], antec_exp);
+ Trace("strings-solve-debug") << "Done, explanation was : " << std::endl;
+ for( unsigned j=ps; j<antec_exp.size(); j++ ){
+ Trace("strings-solve-debug") << " " << antec_exp[j] << std::endl;
+ }
+ Trace("strings-solve-debug") << std::endl;
+ }
+ for( unsigned i=0; i<an.size(); i++ ){
+ Trace("strings-solve-debug") << "Add to explanation (new literal) " << an[i] << std::endl;
+ antec_exp.push_back(an[i]);
+ }
+ Node ant;
+ if( antec_exp.empty() ) {
+ ant = d_true;
+ } else if( antec_exp.size()==1 ) {
+ ant = antec_exp[0];
+ } else {
+ ant = NodeManager::currentNM()->mkNode( kind::AND, antec_exp );
+ }
+ ant = Rewriter::rewrite( ant );
+ return ant;
+}
+
+bool TheoryStrings::checkNormalForms() {
+ Trace("strings-process") << "Normalize equivalence classes...." << std::endl;
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
+ for( unsigned t=0; t<2; t++ ){
+ 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() );
+ if (print) {
+ eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ Trace("strings-eqc") << "Eqc( " << eqc << " ) : ";
+ while( !eqc2_i.isFinished() ) {
+ if( (*eqc2_i)!=eqc ){
+ Trace("strings-eqc") << (*eqc2_i) << " ";
+ }
+ ++eqc2_i;
+ }
+ Trace("strings-eqc") << std::endl;
+ }
+ ++eqcs2_i;
+ }
+ Trace("strings-eqc") << std::endl;
+ }
+ Trace("strings-eqc") << std::endl;
+ for( NodeListMap::const_iterator it = d_nf_pairs.begin(); it != d_nf_pairs.end(); ++it ){
+ NodeList* lst = (*it).second;
+ NodeList::const_iterator it2 = lst->begin();
+ Trace("strings-nf") << (*it).first << " has been unified with ";
+ while( it2!=lst->end() ){
+ Trace("strings-nf") << (*it2);
+ ++it2;
+ }
+ Trace("strings-nf") << std::endl;
+ }
+ Trace("strings-nf") << std::endl;
+ Trace("strings-nf") << "Current inductive equations : " << std::endl;
+ for( NodeListMap::const_iterator it = d_ind_map1.begin(); it != d_ind_map1.end(); ++it ){
+ Node x = (*it).first;
+ NodeList* lst1 = (*it).second;
+ NodeList* lst2 = (*d_ind_map2.find(x)).second;
+ NodeList::const_iterator i1 = lst1->begin();
+ NodeList::const_iterator i2 = lst2->begin();
+ while( i1!=lst1->end() ){
+ Node y = *i1;
+ Node z = *i2;
+ Trace("strings-nf") << "Inductive equation : " << x << " = ( " << y << " ++ " << z << " ) * " << y << std::endl;
+ ++i1;
+ ++i2;
+ }
+ }
+
+ bool addedFact;
+ do {
+ Trace("strings-process") << "Check Normal Forms........next round" << std::endl;
+ //calculate normal forms for each equivalence class, possibly adding splitting lemmas
+ d_normal_forms.clear();
+ d_normal_forms_exp.clear();
+ std::map< Node, Node > nf_to_eqc;
+ std::map< Node, Node > eqc_to_exp;
+ d_lemma_cache.clear();
+ d_pending_req_phase.clear();
+ //get equivalence classes
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ Node eqc = eqcs[i];
+ Trace("strings-process") << "- Verify normal forms are the same for " << eqc << std::endl;
+ std::vector< Node > visited;
+ std::vector< Node > nf;
+ std::vector< Node > nf_exp;
+ normalizeEquivalenceClass(eqc, visited, nf, nf_exp);
+ if( d_conflict ){
+ return true;
+ }else if ( d_pending.empty() && d_lemma_cache.empty() ){
+ Node nf_term;
+ if( nf.size()==0 ){
+ nf_term = d_emptyString;
+ }else if( nf.size()==1 ) {
+ nf_term = nf[0];
+ } else {
+ nf_term = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, nf );
+ }
+ nf_term = Rewriter::rewrite( nf_term );
+ Trace("strings-debug") << "Make nf_term_exp..." << std::endl;
+ Node nf_term_exp = nf_exp.empty() ? d_true :
+ nf_exp.size()==1 ? nf_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, nf_exp );
+ if( nf_to_eqc.find(nf_term)!=nf_to_eqc.end() ){
+ //Trace("strings-debug") << "Merge because of normal form : " << eqc << " and " << nf_to_eqc[nf_term] << " both have normal form " << nf_term << std::endl;
+ //two equivalence classes have same normal form, merge
+ Node eq_exp = NodeManager::currentNM()->mkNode( kind::AND, nf_term_exp, eqc_to_exp[nf_to_eqc[nf_term]] );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, eqc, nf_to_eqc[nf_term] );
+ Trace("strings-lemma") << "Strings (by normal forms) : Infer " << eq << " from " << eq_exp << std::endl;
+ //d_equalityEngine.assertEquality( eq, true, eq_exp );
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ }else{
+ nf_to_eqc[nf_term] = eqc;
+ eqc_to_exp[eqc] = nf_term_exp;
+ }
+ }
+ Trace("strings-process") << "Done verifying normal forms are the same for " << eqc << std::endl;
+ }
+
+ Trace("strings-nf-debug") << "**** Normal forms are : " << std::endl;
+ for( std::map< Node, Node >::iterator it = nf_to_eqc.begin(); it != nf_to_eqc.end(); ++it ){
+ Trace("strings-nf-debug") << " normal_form(" << it->second << ") = " << it->first << std::endl;
+ }
+ Trace("strings-nf-debug") << std::endl;
+ addedFact = !d_pending.empty();
+ doPendingFacts();
+ } while ( !d_conflict && d_lemma_cache.empty() && addedFact );
+
+
+ //process disequalities between equivalence classes
+ if( !d_conflict && d_lemma_cache.empty() ){
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ seperateByLength( eqcs, cols, lts );
+ for( unsigned i=0; i<cols.size(); i++ ){
+ if( cols[i].size()>1 && d_lemma_cache.empty() ){
+ Trace("strings-solve") << "- Verify disequalities are processed for ";
+ printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ //must ensure that normal forms are disequal
+ for( unsigned j=1; j<cols[i].size(); j++ ){
+ if( !d_equalityEngine.areDisequal( cols[i][0], cols[i][j], false ) ){
+ sendSplit( cols[i][0], cols[i][j], "Disequality Normalization" );
+ break;
+ }else{
+ Trace("strings-solve") << " against ";
+ printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ if( normalizeDisequality( cols[i][0], cols[i][j] ) ){
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //flush pending lemmas
+ if( !d_conflict && !d_lemma_cache.empty() ){
+ doPendingLemmas();
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool TheoryStrings::checkCardinality() {
+ int cardinality = options::stringCharCardinality();
+ Trace("strings-solve-debug2") << "get cardinality: " << cardinality << endl;
+
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ seperateByLength( eqcs, cols, lts );
+
+ for( unsigned i = 0; i<cols.size(); ++i ){
+ Node lr = lts[i];
+ Trace("string-cardinality") << "Number of strings with length equal to " << lr << " is " << cols[i].size() << std::endl;
+ // size > c^k
+ double k = std::log( cols[i].size() ) / log((double) cardinality);
+ unsigned int int_k = (unsigned int)k;
+ Node k_node = NodeManager::currentNM()->mkConst( ::CVC4::Rational( int_k ) );
+ //double c_k = pow ( (double)cardinality, (double)lr );
+ if( cols[i].size() > 1 ) {
+ bool allDisequal = true;
+ for( std::vector< Node >::iterator itr1 = cols[i].begin();
+ itr1 != cols[i].end(); ++itr1) {
+ for( std::vector< Node >::iterator itr2 = itr1 + 1;
+ itr2 != cols[i].end(); ++itr2) {
+ if(!d_equalityEngine.areDisequal( *itr1, *itr2, false )) {
+ allDisequal = false;
+ // add split lemma
+ sendSplit( *itr1, *itr2, "Cardinality" );
+ doPendingLemmas();
+ return true;
+ }
+ }
+ }
+ if(allDisequal) {
+ EqcInfo* ei = getOrMakeEqcInfo( lr, true );
+ Trace("string-cardinality") << "Previous cardinality used for " << lr << " is " << ((int)ei->d_cardinality_lem_k.get()-1) << std::endl;
+ if( int_k+1 > ei->d_cardinality_lem_k.get() ){
+ //add cardinality lemma
+ Node dist = NodeManager::currentNM()->mkNode( kind::DISTINCT, cols[i] );
+ std::vector< Node > vec_node;
+ vec_node.push_back( dist );
+ for( std::vector< Node >::iterator itr1 = cols[i].begin();
+ itr1 != cols[i].end(); ++itr1) {
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr1 );
+ if( len!=lr ){
+ Node len_eq_lr = NodeManager::currentNM()->mkNode( kind::EQUAL, lr, len );
+ vec_node.push_back( len_eq_lr );
+ }
+ }
+ Node antc = NodeManager::currentNM()->mkNode( kind::AND, vec_node );
+ Node len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, cols[i][0] );
+ Node cons = NodeManager::currentNM()->mkNode( kind::GT, len, k_node );
+ /*
+ sendLemma( antc, cons, "Cardinality" );
+ ei->d_cardinality_lem_k.set( int_k+1 );
+ if( !d_lemma_cache.empty() ){
+ doPendingLemmas();
+ return true;
+ }
+ */
+ Node lemma = NodeManager::currentNM()->mkNode( kind::IMPLIES, antc, cons );
+ lemma = Rewriter::rewrite( lemma );
+ ei->d_cardinality_lem_k.set( int_k+1 );
+ if( lemma!=d_true ){
+ Trace("strings-lemma") << "Strings cardinality lemma : " << lemma << std::endl;
+ d_out->lemma(lemma);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+int TheoryStrings::gcd ( int a, int b ) {
+ int c;
+ while ( a != 0 ) {
+ c = a; a = b%a; b = c;
+ }
+ return b;
+}
+
+bool TheoryStrings::checkInductiveEquations() {
+ bool hasEq = false;
+ if(d_ind_map1.size() != 0){
+ Trace("strings-ind") << "We are sat, with these inductive equations : " << std::endl;
+ for( NodeListMap::const_iterator it = d_ind_map1.begin(); it != d_ind_map1.end(); ++it ){
+ Node x = (*it).first;
+ Trace("strings-ind-debug") << "Check eq for " << x << std::endl;
+ NodeList* lst1 = (*it).second;
+ NodeList* lst2 = (*d_ind_map2.find(x)).second;
+ NodeList* lste = (*d_ind_map_exp.find(x)).second;
+ //NodeList* lstl = (*d_ind_map_lemma.find(x)).second;
+ NodeList::const_iterator i1 = lst1->begin();
+ NodeList::const_iterator i2 = lst2->begin();
+ NodeList::const_iterator ie = lste->begin();
+ //NodeList::const_iterator il = lstl->begin();
+ while( i1!=lst1->end() ){
+ Node y = *i1;
+ Node z = *i2;
+ //Trace("strings-ind-debug") << "Check y=" << y << " , z=" << z << std::endl;
+ //if( il==lstl->end() ) {
+ std::vector< Node > nf_y, nf_z, exp_y, exp_z;
+
+ //getFinalNormalForm( y, nf_y, exp_y);
+ //getFinalNormalForm( z, nf_z, exp_z);
+ //std::vector< Node > vec_empty;
+ //Node nexp_y = mkExplain( exp_y, vec_empty );
+ //Trace("strings-ind-debug") << "Check nexp_y=" << nexp_y << std::endl;
+ //Node nexp_z = mkExplain( exp_z, vec_empty );
+
+ //Node exp = *ie;
+ //Trace("strings-ind-debug") << "Check exp=" << exp << std::endl;
+
+ //exp = NodeManager::currentNM()->mkNode( kind::AND, exp, nexp_y, nexp_z );
+ //exp = Rewriter::rewrite( exp );
+
+ Trace("strings-ind") << "Inductive equation : " << x << " = ( " << y << " ++ " << z << " )* " << y << std::endl;
+ /*
+ for( std::vector< Node >::const_iterator itr = nf_y.begin(); itr != nf_y.end(); ++itr) {
+ Trace("strings-ind") << (*itr) << " ";
+ }
+ Trace("strings-ind") << " ++ ";
+ for( std::vector< Node >::const_iterator itr = nf_z.begin(); itr != nf_z.end(); ++itr) {
+ Trace("strings-ind") << (*itr) << " ";
+ }
+ Trace("strings-ind") << " )* ";
+ for( std::vector< Node >::const_iterator itr = nf_y.begin(); itr != nf_y.end(); ++itr) {
+ Trace("strings-ind") << (*itr) << " ";
+ }
+ Trace("strings-ind") << std::endl;
+ */
+ /*
+ Trace("strings-ind") << "Explanation is : " << exp << std::endl;
+ std::vector< Node > nf_yz;
+ nf_yz.insert( nf_yz.end(), nf_y.begin(), nf_y.end() );
+ nf_yz.insert( nf_yz.end(), nf_z.begin(), nf_z.end() );
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ seperateByLength( nf_yz, cols, lts );
+ Trace("strings-ind") << "This can be grouped into collections : " << std::endl;
+ for( unsigned j=0; j<cols.size(); j++ ){
+ Trace("strings-ind") << " : ";
+ for( unsigned k=0; k<cols[j].size(); k++ ){
+ Trace("strings-ind") << cols[j][k] << " ";
+ }
+ Trace("strings-ind") << std::endl;
+ }
+ Trace("strings-ind") << std::endl;
+
+ Trace("strings-ind") << "Add length lemma..." << std::endl;
+ std::vector< int > co;
+ co.push_back(0);
+ for(unsigned int k=0; k<lts.size(); ++k) {
+ if(lts[k].isConst() && lts[k].getType().isInteger()) {
+ int len = lts[k].getConst<Rational>().getNumerator().toUnsignedInt();
+ co[0] += cols[k].size() * len;
+ } else {
+ co.push_back( cols[k].size() );
+ }
+ }
+ int g_co = co[0];
+ for(unsigned k=1; k<co.size(); ++k) {
+ g_co = gcd(g_co, co[k]);
+ }
+ Node lemma_len;
+ // both constants
+ Node len_x = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, x );
+ Node sk = NodeManager::currentNM()->mkSkolem( "argsym_$$", NodeManager::currentNM()->integerType(), "created for length inductive lemma" );
+ Node g_co_node = NodeManager::currentNM()->mkConst( CVC4::Rational(g_co) );
+ Node sk_m_gcd = NodeManager::currentNM()->mkNode( kind::MULT, g_co_node, sk );
+ Node len_y = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, y );
+ Node sk_m_g_p_y = NodeManager::currentNM()->mkNode( kind::PLUS, sk_m_gcd, len_y );
+ lemma_len = NodeManager::currentNM()->mkNode( kind::EQUAL, sk_m_g_p_y, len_x );
+ //Node sk_geq_zero = NodeManager::currentNM()->mkNode( kind::GEQ, sk, d_zero );
+ //lemma_len = NodeManager::currentNM()->mkNode( kind::AND, lemma_len, sk_geq_zero );
+ lemma_len = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, lemma_len );
+ Trace("strings-lemma") << "Strings: Add lemma " << lemma_len << std::endl;
+ d_out->lemma(lemma_len);
+ lstl->push_back( d_true );
+ return true;*/
+ //}
+ ++i1;
+ ++i2;
+ ++ie;
+ //++il;
+ if( !d_equalityEngine.hasTerm( d_emptyString ) || !d_equalityEngine.areEqual( y, d_emptyString ) || !d_equalityEngine.areEqual( x, d_emptyString ) ){
+ hasEq = true;
+ }
+ }
+ }
+ }
+ if( hasEq ){
+ Trace("strings-ind") << "It is incomplete." << std::endl;
+ d_out->setIncomplete();
+ }else{
+ Trace("strings-ind") << "We can answer SAT." << std::endl;
+ }
+ return false;
+}
+
+void TheoryStrings::getEquivalenceClasses( std::vector< Node >& eqcs ) {
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ) {
+ Node eqc = (*eqcs_i);
+ //if eqc.getType is string
+ if (eqc.getType().isString()) {
+ eqcs.push_back( eqc );
+ }
+ ++eqcs_i;
+ }
+}
+
+void TheoryStrings::getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp ) {
+ if( n!=d_emptyString ){
+ if( n.getKind()==kind::STRING_CONCAT ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getFinalNormalForm( n[i], nf, exp );
+ }
+ }else{
+ Trace("strings-debug") << "Get final normal form " << n << std::endl;
+ Assert( d_equalityEngine.hasTerm( n ) );
+ Node nr = d_equalityEngine.getRepresentative( n );
+ EqcInfo *eqc_n = getOrMakeEqcInfo( nr, false );
+ Node nc = eqc_n ? eqc_n->d_const_term.get() : Node::null();
+ if( !nc.isNull() ){
+ nf.push_back( nc );
+ if( n!=nc ){
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nc ) );
+ }
+ }else{
+ Assert( d_normal_forms.find( nr )!=d_normal_forms.end() );
+ if( d_normal_forms[nr][0]==nr ){
+ Assert( d_normal_forms[nr].size()==1 );
+ nf.push_back( nr );
+ if( n!=nr ){
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nr ) );
+ }
+ }else{
+ for( unsigned i=0; i<d_normal_forms[nr].size(); i++ ){
+ Assert( d_normal_forms[nr][i]!=nr );
+ getFinalNormalForm( d_normal_forms[nr][i], nf, exp );
+ }
+ exp.insert( exp.end(), d_normal_forms_exp[nr].begin(), d_normal_forms_exp[nr].end() );
+ }
+ }
+ Trace("strings-ind-nf") << "The final normal form of " << n << " is " << nf << std::endl;
+ }
+ }
+}
+
+void TheoryStrings::seperateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& cols,
+ std::vector< Node >& lts ) {
+ unsigned leqc_counter = 0;
+ std::map< Node, unsigned > eqc_to_leqc;
+ std::map< unsigned, Node > leqc_to_eqc;
+ std::map< unsigned, std::vector< Node > > eqc_to_strings;
+ for( unsigned i=0; i<n.size(); i++ ){
+ Node eqc = n[i];
+ Assert( d_equalityEngine.getRepresentative(eqc)==eqc );
+ EqcInfo* ei = getOrMakeEqcInfo( eqc, false );
+ Node lt = ei ? ei->d_length_term : Node::null();
+ if( !lt.isNull() ){
+ lt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
+ Node r = d_equalityEngine.getRepresentative( lt );
+ if( eqc_to_leqc.find( r )==eqc_to_leqc.end() ){
+ eqc_to_leqc[r] = leqc_counter;
+ leqc_to_eqc[leqc_counter] = r;
+ leqc_counter++;
+ }
+ eqc_to_strings[ eqc_to_leqc[r] ].push_back( eqc );
+ }else{
+ eqc_to_strings[leqc_counter].push_back( eqc );
+ leqc_counter++;
+ }
+ }
+ for( std::map< unsigned, std::vector< Node > >::iterator it = eqc_to_strings.begin(); it != eqc_to_strings.end(); ++it ){
+ std::vector< Node > vec;
+ vec.insert( vec.end(), it->second.begin(), it->second.end() );
+ lts.push_back( leqc_to_eqc[it->first] );
+ cols.push_back( vec );
+ }
+}
+
+void TheoryStrings::printConcat( std::vector< Node >& n, const char * c ) {
+ for( unsigned i=0; i<n.size(); i++ ){
+ if( i>0 ) Trace(c) << " ++ ";
+ Trace(c) << n[i];
+ }
+}
+
+/*
+Node TheoryStrings::getNextDecisionRequest() {
+ if( d_lit_to_decide_index.get()<d_lit_to_decide.size() ){
+ Node l = d_lit_to_decide[d_lit_to_decide_index.get()];
+ d_lit_to_decide_index.set( d_lit_to_decide_index.get() + 1 );
+ Trace("strings-ind") << "Strings-ind : decide on " << l << std::endl;
+ return l;
+ }else{
+ return Node::null();
+ }
+}
+*/
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
new file mode 100644
index 000000000..6b8144d6e
--- /dev/null
+++ b/src/theory/strings/theory_strings.h
@@ -0,0 +1,244 @@
+/********************* */
+/*! \file theory_strings.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Theory of strings
+ **
+ ** Theory of strings.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__THEORY_STRINGS_H
+#define __CVC4__THEORY__STRINGS__THEORY_STRINGS_H
+
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+
+#include "context/cdchunk_list.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+/**
+ * Decision procedure for strings.
+ *
+ */
+
+class TheoryStrings : public Theory {
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ public:
+
+ TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+ ~TheoryStrings();
+
+ void setMasterEqualityEngine(eq::EqualityEngine* eq);
+
+ std::string identify() const { return std::string("TheoryStrings"); }
+
+ Node getRepresentative( Node t );
+ bool hasTerm( Node a );
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+ Node getLength( Node t );
+ public:
+
+ void propagate(Effort e);
+ bool propagate(TNode literal);
+ void explain( TNode literal, std::vector<TNode>& assumptions );
+ Node explain( TNode literal );
+
+
+ // NotifyClass for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ TheoryStrings& d_str;
+ public:
+ NotifyClass(TheoryStrings& t_str): d_str(t_str) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
+ if (value) {
+ return d_str.propagate(equality);
+ } else {
+ // We use only literal triggers so taking not is safe
+ return d_str.propagate(equality.notNode());
+ }
+ }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ return d_str.propagate(predicate);
+ } else {
+ return d_str.propagate(predicate.notNode());
+ }
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
+ if (value) {
+ return d_str.propagate(t1.eqNode(t2));
+ } else {
+ return d_str.propagate(t1.eqNode(t2).notNode());
+ }
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
+ d_str.conflict(t1, t2);
+ }
+ void eqNotifyNewClass(TNode t) {
+ Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
+ d_str.eqNotifyNewClass(t);
+ }
+ void eqNotifyPreMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
+ d_str.eqNotifyPreMerge(t1, t2);
+ }
+ void eqNotifyPostMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
+ d_str.eqNotifyPostMerge(t1, t2);
+ }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl;
+ d_str.eqNotifyDisequal(t1, t2, reason);
+ }
+ };/* class TheoryStrings::NotifyClass */
+
+ private:
+ /** The notify class */
+ NotifyClass d_notify;
+ /** Equaltity engine */
+ eq::EqualityEngine d_equalityEngine;
+ /** Are we in conflict */
+ context::CDO<bool> d_conflict;
+ std::vector< Node > d_length_intro_vars;
+ Node d_emptyString;
+ Node d_true;
+ Node d_false;
+ Node d_zero;
+ //list of pairs of nodes to merge
+ std::map< Node, Node > d_pending_exp;
+ std::vector< Node > d_pending;
+ std::vector< Node > d_lemma_cache;
+ std::map< Node, bool > d_pending_req_phase;
+ /** inferences */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+ //map of pairs of terms that have the same normal form
+ NodeListMap d_nf_pairs;
+ void addNormalFormPair( Node n1, Node n2 );
+ bool isNormalFormPair( Node n1, Node n2 );
+ bool isNormalFormPair2( Node n1, Node n2 );
+
+ NodeListMap d_ind_map1;
+ NodeListMap d_ind_map2;
+ NodeListMap d_ind_map_exp;
+ NodeListMap d_ind_map_lemma;
+ bool addInductiveEquation( Node x, Node y, Node z, Node exp, const char * c );
+
+ //for unrolling inductive equations
+ NodeBoolMap d_lit_to_unroll;
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MODEL GENERATION
+ /////////////////////////////////////////////////////////////////////////////
+ public:
+
+ void collectModelInfo(TheoryModel* m, bool fullModel);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // NOTIFICATIONS
+ /////////////////////////////////////////////////////////////////////////////
+
+ public:
+
+ void shutdown() { }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MAIN SOLVER
+ /////////////////////////////////////////////////////////////////////////////
+ private:
+ void addSharedTerm(TNode n);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ private:
+ class EqcInfo
+ {
+ public:
+ EqcInfo( context::Context* c );
+ ~EqcInfo(){}
+ //constant in this eqc
+ context::CDO< Node > d_const_term;
+ context::CDO< Node > d_length_term;
+ context::CDO< unsigned > d_cardinality_lem_k;
+ };
+ /** map from representatives to information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ EqcInfo * getOrMakeEqcInfo( Node eqc, bool doMake = true );
+ //maintain which concat terms have the length lemma instantiatied
+ std::map< Node, bool > d_length_inst;
+ private:
+ std::map< Node, std::vector< Node > > d_normal_forms;
+ std::map< Node, std::vector< Node > > d_normal_forms_exp;
+ void getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
+ std::vector< std::vector< Node > > &normal_forms, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< Node > &normal_form_src);
+ void normalizeEquivalenceClass( Node n, std::vector< Node > & visited, std::vector< Node > & nf, std::vector< Node > & nf_exp );
+ bool normalizeDisequality( Node n1, Node n2 );
+
+ bool checkNormalForms();
+ bool checkCardinality();
+ bool checkInductiveEquations();
+ int gcd(int a, int b);
+ public:
+ void preRegisterTerm(TNode n);
+ void check(Effort e);
+
+ /** Conflict when merging two constants */
+ void conflict(TNode a, TNode b);
+ /** called when a new equivalance class is created */
+ void eqNotifyNewClass(TNode t);
+ /** called when two equivalance classes will merge */
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalance classes have merged */
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes are made disequal */
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+protected:
+ /** compute care graph */
+ void computeCareGraph();
+
+ //do pending merges
+ void doPendingFacts();
+ void doPendingLemmas();
+
+ void sendLemma( Node ant, Node conc, const char * c );
+ void sendSplit( Node a, Node b, const char * c );
+ /** mkConcat **/
+ Node mkConcat( std::vector< Node >& c );
+ /** mkExplain **/
+ Node mkExplain( std::vector< Node >& a, std::vector< Node >& an );
+
+ //get equivalence classes
+ void getEquivalenceClasses( std::vector< Node >& eqcs );
+ //get final normal form
+ void getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp );
+
+ //seperate into collections with equal length
+ void seperateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& col, std::vector< Node >& lts );
+private:
+ void printConcat( std::vector< Node >& n, const char * c );
+};/* class TheoryStrings */
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_H */
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
new file mode 100644
index 000000000..8fa4345e5
--- /dev/null
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -0,0 +1,135 @@
+/********************* */
+/*! \file theory_strings_preprocess.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: Tianyi Liang, Andrew Reynolds
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Strings Preprocess
+ **
+ ** Strings Preprocess.
+ **/
+
+#include "theory/strings/theory_strings_preprocess.h"
+#include "expr/kind.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+void StringsPreprocess::simplifyRegExp( Node s, Node r, std::vector< Node > &ret ) {
+ int k = r.getKind();
+ switch( k ) {
+ case kind::STRING_TO_REGEXP:
+ {
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, s, r[0] );
+ ret.push_back( eq );
+ }
+ break;
+ case kind::REGEXP_CONCAT:
+ {
+ std::vector< Node > cc;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node sk = NodeManager::currentNM()->mkSkolem( "recsym_$$", s.getType(), "created for regular expression concat" );
+ simplifyRegExp( sk, r[i], ret );
+ cc.push_back( sk );
+ }
+ Node cc_eq = NodeManager::currentNM()->mkNode( kind::EQUAL, s,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, cc ) );
+ ret.push_back( cc_eq );
+ }
+ break;
+ case kind::REGEXP_OR:
+ {
+ std::vector< Node > c_or;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ simplifyRegExp( s, r[i], c_or );
+ }
+ Node eq = NodeManager::currentNM()->mkNode( kind::OR, c_or );
+ ret.push_back( eq );
+ }
+ break;
+ case kind::REGEXP_INTER:
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ simplifyRegExp( s, r[i], ret );
+ }
+ break;
+ case kind::REGEXP_STAR:
+ {
+ Node sk = NodeManager::currentNM()->mkSkolem( "ressym_$$", s.getType(), "created for regular expression star" );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk, s ),
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, s, sk ));
+ ret.push_back( eq );
+ simplifyRegExp( sk, r[0], ret );
+ }
+ break;
+ case kind::REGEXP_OPT:
+ {
+ Node eq_empty = NodeManager::currentNM()->mkNode( kind::EQUAL, s, NodeManager::currentNM()->mkConst( ::CVC4::String("") ) );
+ std::vector< Node > rr;
+ simplifyRegExp( s, r[0], rr );
+ Node nrr = rr.size()==1 ? rr[0] : NodeManager::currentNM()->mkNode( kind::AND, rr );
+ ret.push_back( NodeManager::currentNM()->mkNode( kind::OR, eq_empty, nrr) );
+ }
+ break;
+ default:
+ //TODO:case kind::REGEXP_PLUS:
+ //TODO: special sym: sigma, none, all
+ break;
+ }
+}
+
+Node StringsPreprocess::simplify( Node t ) {
+ std::hash_map<TNode, Node, TNodeHashFunction>::const_iterator i = d_cache.find(t);
+ if(i != d_cache.end()) {
+ return (*i).second.isNull() ? t : (*i).second;
+ }
+
+ if( t.getKind() == kind::STRING_IN_REGEXP ){
+ // t0 in t1
+ //rewrite it
+ std::vector< Node > ret;
+ simplifyRegExp( t[0], t[1], ret );
+
+ Node n = ret.size() == 1 ? ret[0] : NodeManager::currentNM()->mkNode( kind::AND, ret );
+ d_cache[t] = (t == n) ? Node::null() : n;
+ return n;
+ }else if( t.getNumChildren()>0 ){
+ std::vector< Node > cc;
+ if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ cc.push_back(t.getOperator());
+ }
+ bool changed = false;
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node tn = simplify( t[i] );
+ cc.push_back( tn );
+ changed = changed || tn!=t[i];
+ }
+ if(changed) {
+ Node n = NodeManager::currentNM()->mkNode( t.getKind(), cc );
+ d_cache[t] = n;
+ return n;
+ } else {
+ d_cache[t] = Node::null();
+ return t;
+ }
+ }else{
+ d_cache[t] = Node::null();
+ return t;
+ }
+}
+
+void StringsPreprocess::simplify(std::vector< Node > &vec_node) {
+ for( unsigned i=0; i<vec_node.size(); i++ ){
+ vec_node[i] = simplify( vec_node[i] );
+ }
+}
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
new file mode 100644
index 000000000..f82a3cf24
--- /dev/null
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -0,0 +1,44 @@
+/********************* */
+/*! \file theory_strings_preprocess.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: Tianyi Liang, Andrew Reynolds
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Strings Preprocess
+ **
+ ** Strings Preprocess.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__PREPROCESS_H
+#define __CVC4__THEORY__STRINGS__PREPROCESS_H
+
+#include <vector>
+#include "util/hash.h"
+#include "theory/theory.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class StringsPreprocess {
+ // NOTE: this class is NOT context-dependent
+ std::hash_map<TNode, Node, TNodeHashFunction> d_cache;
+private:
+ void simplifyRegExp( Node s, Node r, std::vector< Node > &ret );
+ Node simplify( Node t );
+public:
+void simplify(std::vector< Node > &vec_node);
+};
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__PREPROCESS_H */
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
new file mode 100644
index 000000000..412135675
--- /dev/null
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -0,0 +1,156 @@
+/********************* */
+/*! \file theory_strings_rewriter.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of the theory of strings.
+ **
+ ** Implementation of the theory of strings.
+ **/
+#include "theory/strings/theory_strings_rewriter.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::strings;
+
+Node TheoryStringsRewriter::rewriteConcatString(TNode node) {
+ Trace("strings-prerewrite") << "Strings::rewriteConcatString start " << node << std::endl;
+ Node retNode = node;
+ std::vector<Node> node_vec;
+ Node preNode = Node::null();
+ for(unsigned int i=0; i<node.getNumChildren(); ++i) {
+ Node tmpNode = node[i];
+ if(node[i].getKind() == kind::STRING_CONCAT) {
+ tmpNode = rewriteConcatString(node[i]);
+ if(tmpNode.getKind() == kind::STRING_CONCAT) {
+ unsigned int j=0;
+ if(!preNode.isNull()) {
+ if(tmpNode[0].isConst()) {
+ preNode = NodeManager::currentNM()->mkConst( preNode.getConst<String>().concat( tmpNode[0].getConst<String>() ) );
+ node_vec.push_back( preNode );
+ preNode = Node::null();
+ ++j;
+ } else {
+ node_vec.push_back( preNode );
+ preNode = Node::null();
+ node_vec.push_back( tmpNode[0] );
+ ++j;
+ }
+ }
+ for(; j<tmpNode.getNumChildren() - 1; ++j) {
+ node_vec.push_back( tmpNode[j] );
+ }
+ tmpNode = tmpNode[j];
+ }
+ }
+ if(!tmpNode.isConst()) {
+ if(preNode != Node::null()) {
+ if(preNode.getKind() == kind::CONST_STRING && preNode.getConst<String>().toString()=="" ) {
+ preNode = Node::null();
+ } else {
+ node_vec.push_back( preNode );
+ preNode = Node::null();
+ }
+ }
+ node_vec.push_back( tmpNode );
+ } else {
+ if(preNode.isNull()) {
+ preNode = tmpNode;
+ } else {
+ preNode = NodeManager::currentNM()->mkConst( preNode.getConst<String>().concat( tmpNode.getConst<String>() ) );
+ }
+ }
+ }
+ if(preNode != Node::null()) {
+ node_vec.push_back( preNode );
+ }
+ if(node_vec.size() > 1) {
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, node_vec);
+ } else {
+ retNode = node_vec[0];
+ }
+ Trace("strings-prerewrite") << "Strings::rewriteConcatString end " << retNode << std::endl;
+ return retNode;
+}
+
+RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
+ Trace("strings-postrewrite") << "Strings::postRewrite start " << node << std::endl;
+ Node retNode = node;
+
+ if(node.getKind() == kind::STRING_CONCAT) {
+ retNode = rewriteConcatString(node);
+ } else if(node.getKind() == kind::EQUAL) {
+ Node leftNode = node[0];
+ if(node[0].getKind() == kind::STRING_CONCAT) {
+ leftNode = rewriteConcatString(node[0]);
+ }
+ Node rightNode = node[1];
+ if(node[1].getKind() == kind::STRING_CONCAT) {
+ rightNode = rewriteConcatString(node[1]);
+ }
+
+ if(leftNode == rightNode) {
+ retNode = NodeManager::currentNM()->mkConst(true);
+ } else if(leftNode.isConst() && rightNode.isConst()) {
+ retNode = NodeManager::currentNM()->mkConst(false);
+ } else if(leftNode > rightNode) {
+ retNode = NodeManager::currentNM()->mkNode(kind::EQUAL, rightNode, leftNode);
+ } else if( leftNode != node[0] || rightNode != node[1]) {
+ retNode = NodeManager::currentNM()->mkNode(kind::EQUAL, leftNode, rightNode);
+ }
+ } else if(node.getKind() == kind::STRING_IN_REGEXP) {
+ Node leftNode = node[0];
+ if(node[0].getKind() == kind::STRING_CONCAT) {
+ leftNode = rewriteConcatString(node[0]);
+ }
+ // TODO: right part
+ Node rightNode = node[1];
+ // merge
+ if( leftNode != node[0] || rightNode != node[1]) {
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, leftNode, rightNode);
+ }
+ } else if(node.getKind() == kind::STRING_LENGTH) {
+ if(node[0].isConst()) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( node[0].getConst<String>().size() ) );
+ } else if(node[0].getKind() == kind::STRING_CONCAT) {
+ Node tmpNode = rewriteConcatString(node[0]);
+ if(tmpNode.isConst()) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode.getConst<String>().size() ) );
+ } else {
+ // it has to be string concat
+ std::vector<Node> node_vec;
+ for(unsigned int i=0; i<tmpNode.getNumChildren(); ++i) {
+ if(tmpNode[i].isConst()) {
+ node_vec.push_back( NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode[i].getConst<String>().size() ) ) );
+ } else {
+ node_vec.push_back( NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, tmpNode[i]) );
+ }
+ }
+ retNode = NodeManager::currentNM()->mkNode(kind::PLUS, node_vec);
+ }
+ }
+ }
+
+ Trace("strings-postrewrite") << "Strings::postRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, retNode);
+}
+
+RewriteResponse TheoryStringsRewriter::preRewrite(TNode node) {
+ Node retNode = node;
+ Trace("strings-prerewrite") << "Strings::preRewrite start " << node << std::endl;
+
+ if(node.getKind() == kind::STRING_CONCAT) {
+ retNode = rewriteConcatString(node);
+ }
+
+ Trace("strings-prerewrite") << "Strings::preRewrite returning " << retNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, retNode);
+}
diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h
new file mode 100644
index 000000000..3bccd91de
--- /dev/null
+++ b/src/theory/strings/theory_strings_rewriter.h
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file theory_strings_rewriter.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** 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 "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__THEORY_STRINGS_REWRITER_H
+#define __CVC4__THEORY__STRINGS__THEORY_STRINGS_REWRITER_H
+
+#include "theory/rewriter.h"
+#include "theory/type_enumerator.h"
+#include "expr/attribute.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class TheoryStringsRewriter {
+
+public:
+ static Node rewriteConcatString(TNode node);
+
+ static RewriteResponse postRewrite(TNode node);
+
+ static RewriteResponse preRewrite(TNode node);
+
+ static inline void init() {}
+ static inline void shutdown() {}
+
+};/* class TheoryStringsRewriter */
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_REWRITER_H */
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
new file mode 100644
index 000000000..8fc630206
--- /dev/null
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -0,0 +1,223 @@
+/********************* */
+/*! \file theory_strings_type_rules.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2013-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Typing and cardinality rules for the theory of arrays
+ **
+ ** Typing and cardinality rules for the theory of arrays.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__THEORY_STRINGS_TYPE_RULES_H
+#define __CVC4__THEORY__STRINGS__THEORY_STRINGS_TYPE_RULES_H
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class StringConstantTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return nodeManager->stringType();
+ }
+};
+
+class StringConcatTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms in string concat");
+ }
+ }
+ return nodeManager->stringType();
+ }
+};
+
+class StringLengthTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms in string length");
+ }
+ }
+ return nodeManager->integerType();
+ }
+};
+
+class RegExpConstantTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpConcatTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpOrTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpInterTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ for (; it != it_end; ++ it) {
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpStarTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many regexp");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpPlusTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many regexp");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class RegExpOptTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many regexp");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class StringToRegExpTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms");
+ }
+ if( (*it).getKind() != kind::CONST_STRING ) {
+ throw TypeCheckingExceptionPrivate(n, "expecting constant string terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many terms");
+ }
+
+ return nodeManager->regexpType();
+ }
+};
+
+class StringInRegExpTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ TNode::iterator it = n.begin();
+ TNode::iterator it_end = n.end();
+ TypeNode t = (*it).getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms");
+ }
+ ++it;
+ t = (*it).getType(check);
+ if (!t.isRegExp()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting regexp terms");
+ }
+ if(++it != it_end) {
+ throw TypeCheckingExceptionPrivate(n, "too many terms");
+ }
+
+ return nodeManager->booleanType();
+ }
+};
+
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_TYPE_RULES_H */
diff --git a/src/theory/strings/type_enumerator.h b/src/theory/strings/type_enumerator.h
new file mode 100644
index 000000000..3dc12009b
--- /dev/null
+++ b/src/theory/strings/type_enumerator.h
@@ -0,0 +1,130 @@
+/********************* */
+/*! \file type_enumerator.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Enumerators for strings
+ **
+ ** Enumerators for strings.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__STRINGS__TYPE_ENUMERATOR_H
+#define __CVC4__THEORY__STRINGS__TYPE_ENUMERATOR_H
+
+#include <sstream>
+
+#include "util/regexp.h"
+#include "theory/type_enumerator.h"
+#include "expr/type_node.h"
+#include "expr/kind.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+class StringEnumerator : public TypeEnumeratorBase<StringEnumerator> {
+ std::vector< unsigned > d_data;
+ unsigned d_cardinality;
+ Node d_curr;
+ void mkCurr() {
+ //make constant from d_data
+ d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
+ }
+public:
+
+ StringEnumerator(TypeNode type) throw(AssertionException) :
+ TypeEnumeratorBase<StringEnumerator>(type) {
+ Assert(type.getKind() == kind::TYPE_CONSTANT &&
+ type.getConst<TypeConstant>() == STRING_TYPE);
+ d_cardinality = 256;
+ mkCurr();
+ }
+ Node operator*() throw() {
+ return d_curr;
+ }
+ StringEnumerator& operator++() throw() {
+ bool changed = false;
+ do{
+ for(unsigned i=0; i<d_data.size(); ++i) {
+ if( d_data[i] + 1 < d_cardinality ) {
+ ++d_data[i]; changed = true;
+ break;
+ } else {
+ d_data[i] = 0;
+ }
+ }
+
+ if(!changed) {
+ d_data.push_back( 0 );
+ }
+ }while(!changed);
+
+ mkCurr();
+ return *this;
+ }
+
+ bool isFinished() throw() {
+ return d_curr.isNull();
+ }
+
+};/* class StringEnumerator */
+
+
+class StringEnumeratorLength {
+private:
+ unsigned d_cardinality;
+ std::vector< unsigned > d_data;
+ Node d_curr;
+ void mkCurr() {
+ //make constant from d_data
+ d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
+ }
+public:
+ StringEnumeratorLength(unsigned length, unsigned card = 256) : d_cardinality(card) {
+ for( unsigned i=0; i<length; i++ ){
+ d_data.push_back( 0 );
+ }
+ mkCurr();
+ }
+
+ Node operator*() throw() {
+ return d_curr;
+ }
+
+ StringEnumeratorLength& operator++() throw() {
+ bool changed = false;
+ for(unsigned i=0; i<d_data.size(); ++i) {
+ if( d_data[i] + 1 < d_cardinality ) {
+ ++d_data[i]; changed = true;
+ break;
+ } else {
+ d_data[i] = 0;
+ }
+ }
+
+ if(!changed) {
+ d_curr = Node::null();
+ }else{
+ mkCurr();
+ }
+ return *this;
+ }
+
+ bool isFinished() throw() {
+ return d_curr.isNull();
+ }
+};
+
+}/* CVC4::theory::strings namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__STRINGS__TYPE_ENUMERATOR_H */
diff --git a/src/theory/substitutions.cpp b/src/theory/substitutions.cpp
index c12129d01..c4f06e396 100644
--- a/src/theory/substitutions.cpp
+++ b/src/theory/substitutions.cpp
@@ -29,7 +29,7 @@ struct substitution_stack_element {
: node(node), children_added(false) {}
};/* struct substitution_stack_element */
-Node SubstitutionMap::internalSubstitute(TNode t) {
+Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) {
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl;
@@ -50,8 +50,8 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): processing " << current << endl;
// If node already in the cache we're done, pop from the stack
- NodeCache::iterator find = d_substitutionCache.find(current);
- if (find != d_substitutionCache.end()) {
+ NodeCache::iterator find = cache.find(current);
+ if (find != cache.end()) {
toVisit.pop_back();
continue;
}
@@ -59,7 +59,7 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
if (!d_substituteUnderQuantifiers &&
(current.getKind() == kind::FORALL || current.getKind() == kind::EXISTS)) {
Debug("substitution::internal") << "--not substituting under quantifier" << endl;
- d_substitutionCache[current] = current;
+ cache[current] = current;
toVisit.pop_back();
continue;
}
@@ -68,9 +68,9 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
if (find2 != d_substitutions.end()) {
Node rhs = (*find2).second;
Assert(rhs != current);
- internalSubstitute(rhs);
- d_substitutions[current] = d_substitutionCache[rhs];
- d_substitutionCache[current] = d_substitutionCache[rhs];
+ internalSubstitute(rhs, cache);
+ d_substitutions[current] = cache[rhs];
+ cache[current] = cache[rhs];
toVisit.pop_back();
continue;
}
@@ -80,17 +80,17 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
// Children have been processed, so substitute
NodeBuilder<> builder(current.getKind());
if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
- builder << Node(d_substitutionCache[current.getOperator()]);
+ builder << Node(cache[current.getOperator()]);
}
for (unsigned i = 0; i < current.getNumChildren(); ++ i) {
- Assert(d_substitutionCache.find(current[i]) != d_substitutionCache.end());
- builder << Node(d_substitutionCache[current[i]]);
+ Assert(cache.find(current[i]) != cache.end());
+ builder << Node(cache[current[i]]);
}
// Mark the substitution and continue
Node result = builder;
if (result != current) {
- find = d_substitutionCache.find(result);
- if (find != d_substitutionCache.end()) {
+ find = cache.find(result);
+ if (find != cache.end()) {
result = find->second;
}
else {
@@ -98,15 +98,15 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
if (find2 != d_substitutions.end()) {
Node rhs = (*find2).second;
Assert(rhs != result);
- internalSubstitute(rhs);
- d_substitutions[result] = d_substitutionCache[rhs];
- d_substitutionCache[result] = d_substitutionCache[rhs];
- result = d_substitutionCache[rhs];
+ internalSubstitute(rhs, cache);
+ d_substitutions[result] = cache[rhs];
+ cache[result] = cache[rhs];
+ result = cache[rhs];
}
}
}
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << endl;
- d_substitutionCache[current] = result;
+ cache[current] = result;
toVisit.pop_back();
} else {
// Mark that we have added the children if any
@@ -115,34 +115,33 @@ Node SubstitutionMap::internalSubstitute(TNode t) {
// We need to add the operator, if any
if(current.getMetaKind() == kind::metakind::PARAMETERIZED) {
TNode opNode = current.getOperator();
- NodeCache::iterator opFind = d_substitutionCache.find(opNode);
- if (opFind == d_substitutionCache.end()) {
+ NodeCache::iterator opFind = cache.find(opNode);
+ if (opFind == cache.end()) {
toVisit.push_back(opNode);
}
}
// We need to add the children
for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) {
TNode childNode = *child_it;
- NodeCache::iterator childFind = d_substitutionCache.find(childNode);
- if (childFind == d_substitutionCache.end()) {
+ NodeCache::iterator childFind = cache.find(childNode);
+ if (childFind == cache.end()) {
toVisit.push_back(childNode);
}
}
} else {
// No children, so we're done
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << endl;
- d_substitutionCache[current] = current;
+ cache[current] = current;
toVisit.pop_back();
}
}
}
// Return the substituted version
- return d_substitutionCache[t];
+ return cache[t];
}/* SubstitutionMap::internalSubstitute() */
- /*
void SubstitutionMap::simplifyRHS(const SubstitutionMap& subMap)
{
// Put the new substitutions into the old ones
@@ -160,10 +159,10 @@ void SubstitutionMap::simplifyRHS(TNode x, TNode t) {
tempCache[x] = t;
// Put the new substitution into the old ones
- NodeMap::iterator it = d_substitutionsOld.begin();
- NodeMap::iterator it_end = d_substitutionsOld.end();
+ NodeMap::iterator it = d_substitutions.begin();
+ NodeMap::iterator it_end = d_substitutions.end();
for(; it != it_end; ++ it) {
- d_substitutionsOld[(*it).first] = internalSubstituteOld((*it).second, tempCache);
+ d_substitutions[(*it).first] = internalSubstitute((*it).second, tempCache);
}
// it = d_substitutionsLazy.begin();
// it_end = d_substitutionsLazy.end();
@@ -171,7 +170,7 @@ void SubstitutionMap::simplifyRHS(TNode x, TNode t) {
// d_substitutionsLazy[(*it).first] = internalSubstitute((*it).second, tempCache);
// }
}
-*/
+
/* We use subMap to simplify the left-hand sides of the current substitution map. If rewrite is true,
* we also apply the rewriter to the result.
@@ -283,6 +282,24 @@ void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache)
}
}
+
+void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateCache)
+{
+ SubstitutionMap::NodeMap::const_iterator it = subMap.begin();
+ SubstitutionMap::NodeMap::const_iterator it_end = subMap.end();
+ for (; it != it_end; ++ it) {
+ Assert(d_substitutions.find((*it).first) == d_substitutions.end());
+ d_substitutions[(*it).first] = (*it).second;
+ if (!invalidateCache) {
+ d_substitutionCache[(*it).first] = d_substitutions[(*it).first];
+ }
+ }
+ if (invalidateCache) {
+ d_cacheInvalidated = true;
+ }
+}
+
+
static bool check(TNode node, const SubstitutionMap::NodeMap& substitutions) CVC4_UNUSED;
static bool check(TNode node, const SubstitutionMap::NodeMap& substitutions) {
SubstitutionMap::NodeMap::const_iterator it = substitutions.begin();
@@ -311,7 +328,7 @@ Node SubstitutionMap::apply(TNode t) {
}
// Perform the substitution
- Node result = internalSubstitute(t);
+ Node result = internalSubstitute(t, d_substitutionCache);
Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl;
// Assert(check(result, d_substitutions));
diff --git a/src/theory/substitutions.h b/src/theory/substitutions.h
index bde7dfdbc..5a478a250 100644
--- a/src/theory/substitutions.h
+++ b/src/theory/substitutions.h
@@ -68,8 +68,11 @@ private:
/** Has the cache been invalidated? */
bool d_cacheInvalidated;
+ /** Whether to keep substitutions in solved form */
+ bool d_solvedForm;
+
/** Internal method that performs substitution */
- Node internalSubstitute(TNode t);
+ Node internalSubstitute(TNode t, NodeCache& cache);
/** Helper class to invalidate cache on user pop */
class CacheInvalidator : public context::ContextNotifyObj {
@@ -98,13 +101,15 @@ private:
public:
- SubstitutionMap(context::Context* context, bool substituteUnderQuantifiers = true) :
+ SubstitutionMap(context::Context* context, bool substituteUnderQuantifiers = true, bool solvedForm = false) :
d_context(context),
d_substitutions(context),
d_substitutionCache(),
d_substituteUnderQuantifiers(substituteUnderQuantifiers),
d_cacheInvalidated(false),
- d_cacheInvalidator(context, d_cacheInvalidated) {
+ d_solvedForm(solvedForm),
+ d_cacheInvalidator(context, d_cacheInvalidated)
+ {
}
/**
@@ -113,6 +118,11 @@ public:
void addSubstitution(TNode x, TNode t, bool invalidateCache = true);
/**
+ * Merge subMap into current set of substitutions
+ */
+ void addSubstitutions(SubstitutionMap& subMap, bool invalidateCache = true);
+
+ /**
* Returns true iff x is in the substitution map
*/
bool hasSubstitution(TNode x) const {
@@ -170,13 +180,13 @@ public:
// should best interact with cache invalidation on context
// pops.
- /*
// Simplify right-hand sides of current map using the given substitutions
void simplifyRHS(const SubstitutionMap& subMap);
// Simplify right-hand sides of current map with lhs -> rhs
void simplifyRHS(TNode lhs, TNode rhs);
+ /*
// Simplify left-hand sides of current map using the given substitutions
void simplifyLHS(const SubstitutionMap& subMap,
std::vector<std::pair<Node,Node> >& equalities,
@@ -188,6 +198,8 @@ public:
bool rewrite = true);
*/
+ bool isSolvedForm() const { return d_solvedForm; }
+
/**
* Print to the output stream
*/
diff --git a/src/theory/term_registration_visitor.cpp b/src/theory/term_registration_visitor.cpp
index 48d00130c..558975a72 100644
--- a/src/theory/term_registration_visitor.cpp
+++ b/src/theory/term_registration_visitor.cpp
@@ -127,15 +127,6 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
Assert(alreadyVisited(current, parent));
}
-void PreRegisterVisitor::start(TNode node) {
- d_multipleTheories = false;
-}
-
-bool PreRegisterVisitor::done(TNode node) {
- // We have multiple theories if removing the node theory from others is non-empty
- return Theory::setRemove(Theory::theoryOf(node), d_theories);
-}
-
std::string SharedTermsVisitor::toString() const {
std::stringstream ss;
TNodeVisitedMap::const_iterator it = d_visited.begin();
diff --git a/src/theory/term_registration_visitor.h b/src/theory/term_registration_visitor.h
index 768508d2c..478e82d19 100644
--- a/src/theory/term_registration_visitor.h
+++ b/src/theory/term_registration_visitor.h
@@ -55,25 +55,19 @@ class PreRegisterVisitor {
theory::Theory::Set d_theories;
/**
- * Is true if the term we're traversing involves multiple theories.
- */
- bool d_multipleTheories;
-
- /**
* String representation of the visited map, for debugging purposes.
*/
std::string toString() const;
public:
- /** Return type tells us if there are more than one theory or not */
- typedef bool return_type;
+ /** Returned set tells us which theories there are */
+ typedef theory::Theory::Set return_type;
PreRegisterVisitor(TheoryEngine* engine, context::Context* context)
: d_engine(engine)
, d_visited(context)
, d_theories(0)
- , d_multipleTheories(false)
{}
/**
@@ -89,13 +83,12 @@ public:
/**
* Marks the node as the starting literal.
*/
- void start(TNode node);
+ void start(TNode node) { }
/**
* Notifies the engine of all the theories used.
*/
- bool done(TNode node);
-
+ theory::Theory::Set done(TNode node) { return d_theories; }
};
diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp
index 9ed20cc99..9a23d5518 100644
--- a/src/theory/theory.cpp
+++ b/src/theory/theory.cpp
@@ -17,6 +17,7 @@
#include "theory/theory.h"
#include "util/cvc4_assert.h"
#include "theory/quantifiers_engine.h"
+#include "theory/substitutions.h"
#include <vector>
@@ -28,9 +29,6 @@ namespace theory {
/** Default value for the uninterpreted sorts is the UF theory */
TheoryId Theory::s_uninterpretedSortOwner = THEORY_UF;
-/** By default, we use the type based theoryOf */
-TheoryOfMode Theory::s_theoryOfMode = THEORY_OF_TYPE_BASED;
-
std::ostream& operator<<(std::ostream& os, Theory::Effort level){
switch(level){
case Theory::EFFORT_STANDARD:
@@ -72,7 +70,7 @@ TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) {
// Variables
if (node.isVar()) {
if (theoryOf(node.getType()) != theory::THEORY_BOOL) {
- // We treat the varibables as uninterpreted
+ // We treat the variables as uninterpreted
return s_uninterpretedSortOwner;
} else {
// Except for the Boolean ones, which we just ignore anyhow
@@ -209,5 +207,27 @@ void Theory::computeRelevantTerms(set<Node>& termSet)
}
+Theory::PPAssertStatus Theory::ppAssert(TNode in, SubstitutionMap& outSubstitutions)
+{
+ if (in.getKind() == kind::EQUAL) {
+ if (in[0].isVar() && !in[1].hasSubterm(in[0])) {
+ outSubstitutions.addSubstitution(in[0], in[1]);
+ return PP_ASSERT_STATUS_SOLVED;
+ }
+ if (in[1].isVar() && !in[0].hasSubterm(in[1])) {
+ outSubstitutions.addSubstitution(in[1], in[0]);
+ return PP_ASSERT_STATUS_SOLVED;
+ }
+ if (in[0].isConst() && in[1].isConst()) {
+ if (in[0] != in[1]) {
+ return PP_ASSERT_STATUS_CONFLICT;
+ }
+ }
+ }
+
+ return PP_ASSERT_STATUS_UNSOLVED;
+}
+
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 23fd67b23..21a5aacf5 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -23,9 +23,9 @@
#include "expr/attribute.h"
#include "expr/command.h"
#include "theory/valuation.h"
-#include "theory/substitutions.h"
#include "theory/output_channel.h"
#include "theory/logic_info.h"
+#include "theory/options.h"
#include "theory/theoryof_mode.h"
#include "context/context.h"
#include "context/cdlist.h"
@@ -49,6 +49,7 @@ namespace theory {
class QuantifiersEngine;
class TheoryModel;
+class SubstitutionMap;
namespace rrinst {
class CandidateGenerator;
@@ -298,9 +299,6 @@ protected:
void printFacts(std::ostream& os) const;
void debugPrintFacts() const;
- /** Mode of the theoryOf operation */
- static TheoryOfMode s_theoryOfMode;
-
public:
/**
@@ -333,12 +331,7 @@ public:
* Returns the ID of the theory responsible for the given node.
*/
static inline TheoryId theoryOf(TNode node) {
- return theoryOf(s_theoryOfMode, node);
- }
-
- /** Set the theoryOf mode */
- static void setTheoryOfMode(TheoryOfMode mode) {
- s_theoryOfMode = mode;
+ return theoryOf(options::theoryOfMode(), node);
}
/**
@@ -349,7 +342,7 @@ public:
}
/**
- * Set the owner of the uninterpreted sort.
+ * Get the owner of the uninterpreted sort.
*/
static TheoryId getUninterpretedSortOwner() {
return s_uninterpretedSortOwner;
@@ -516,7 +509,7 @@ public:
virtual EqualityStatus getEqualityStatus(TNode a, TNode b) { return EQUALITY_UNKNOWN; }
/**
- * Return the model value of the give shared term (or null if not avalilable.
+ * Return the model value of the give shared term (or null if not available).
*/
virtual Node getModelValue(TNode var) { return Node::null(); }
@@ -583,25 +576,7 @@ public:
* Given a literal, add the solved substitutions to the map, if any.
* The method should return true if the literal can be safely removed.
*/
- virtual PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
- if (in.getKind() == kind::EQUAL) {
- if (in[0].isVar() && !in[1].hasSubterm(in[0])) {
- outSubstitutions.addSubstitution(in[0], in[1]);
- return PP_ASSERT_STATUS_SOLVED;
- }
- if (in[1].isVar() && !in[0].hasSubterm(in[1])) {
- outSubstitutions.addSubstitution(in[1], in[0]);
- return PP_ASSERT_STATUS_SOLVED;
- }
- if (in[0].isConst() && in[1].isConst()) {
- if (in[0] != in[1]) {
- return PP_ASSERT_STATUS_CONFLICT;
- }
- }
- }
-
- return PP_ASSERT_STATUS_UNSOLVED;
- }
+ virtual PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
/**
* Given an atom of the theory coming from the input formula, this
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 6c8341345..78710e4b9 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -110,6 +110,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_propagationMapTimestamp(context, 0),
d_propagatedLiterals(context),
d_propagatedLiteralsIndex(context, 0),
+ d_atomRequests(context),
d_iteRemover(iteRemover),
d_combineTheoriesTime("TheoryEngine::combineTheoriesTime"),
d_true(),
@@ -186,9 +187,32 @@ void TheoryEngine::preRegister(TNode preprocessed) {
}
// Pre-register the terms in the atom
- bool multipleTheories = NodeVisitor<PreRegisterVisitor>::run(d_preRegistrationVisitor, preprocessed);
+ Theory::Set theories = NodeVisitor<PreRegisterVisitor>::run(d_preRegistrationVisitor, preprocessed);
+ theories = Theory::setRemove(THEORY_BOOL, theories);
+ // Remove the top theory, if any more that means multiple theories were involved
+ bool multipleTheories = Theory::setRemove(Theory::theoryOf(preprocessed), theories);
+ TheoryId i;
+ // These checks don't work with finite model finding, because it
+ // uses Rational constants to represent cardinality constraints,
+ // even though arithmetic isn't actually involved.
+ if(!options::finiteModelFind()) {
+ while((i = Theory::setPop(theories)) != THEORY_LAST) {
+ if(!d_logicInfo.isTheoryEnabled(i)) {
+ LogicInfo newLogicInfo = d_logicInfo.getUnlockedCopy();
+ newLogicInfo.enableTheory(i);
+ newLogicInfo.lock();
+ stringstream ss;
+ ss << "The logic was specified as " << d_logicInfo.getLogicString()
+ << ", which doesn't include " << i
+ << ", but found a term in that theory." << endl
+ << "You might want to extend your logic to "
+ << newLogicInfo.getLogicString() << endl;
+ throw LogicException(ss.str());
+ }
+ }
+ }
if (multipleTheories) {
- // Collect the shared terms if there are multipe theories
+ // Collect the shared terms if there are multiple theories
NodeVisitor<SharedTermsVisitor>::run(d_sharedTermsVisitor, preprocessed);
}
}
@@ -204,8 +228,8 @@ void TheoryEngine::printAssertions(const char* tag) {
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
Theory* theory = d_theoryTable[theoryId];
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
- Trace(tag) << "--------------------------------------------" << std::endl;
- Trace(tag) << "Assertions of " << theory->getId() << ": " << std::endl;
+ Trace(tag) << "--------------------------------------------" << endl;
+ Trace(tag) << "Assertions of " << theory->getId() << ": " << endl;
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
for (unsigned i = 0; it != it_end; ++ it, ++i) {
if ((*it).isPreregistered) {
@@ -217,7 +241,7 @@ void TheoryEngine::printAssertions(const char* tag) {
}
if (d_logicInfo.isSharingEnabled()) {
- Trace(tag) << "Shared terms of " << theory->getId() << ": " << std::endl;
+ Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl;
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
for (unsigned i = 0; it != it_end; ++ it, ++i) {
Trace(tag) << "[" << i << "]: " << (*it) << endl;
@@ -287,9 +311,7 @@ void TheoryEngine::check(Theory::Effort effort) {
#endif
#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \
-Debug("theory") << "check<" << THEORY << ">" << std::endl; \
theoryOf(THEORY)->check(effort); \
-Debug("theory") << "done<" << THEORY << ">" << std::endl; \
if (d_inConflict) { \
break; \
} \
@@ -305,7 +327,7 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
// Mark the lemmas flag (no lemmas added)
d_lemmasAdded = false;
- Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl;
// If in full effort, we have a fake new assertion just to jumpstart the checking
if (Theory::fullEffort(effort)) {
@@ -315,9 +337,9 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
// Check until done
while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) {
- Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl;
- Trace("theory::assertions") << std::endl;
+ Trace("theory::assertions") << endl;
if (Trace.isOn("theory::assertions")) {
printAssertions("theory::assertions");
}
@@ -334,7 +356,7 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
<< CheckSatCommand();
}
- Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl;
// We are still satisfiable, propagate as much as possible
propagate(effort);
@@ -342,13 +364,14 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
// We do combination if all has been processed and we are in fullcheck
if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded) {
// Do the combination
- Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
combineTheories();
}
}
// Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma
if( effort == Theory::EFFORT_FULL && ! d_inConflict && ! needCheck() ) {
+ //d_theoryTable[THEORY_STRINGS]->check(Theory::EFFORT_LAST_CALL);
if(d_logicInfo.isQuantified()) {
// quantifiers engine must pass effort last call check
d_quantEngine->check(Theory::EFFORT_LAST_CALL);
@@ -365,7 +388,11 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
}
}
- Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas") << std::endl;
+ Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas") << endl;
+
+ if(!d_inConflict && Theory::fullEffort(effort) && d_masterEqualityEngine != NULL && !d_lemmasAdded) {
+ AlwaysAssert(d_masterEqualityEngine->consistent());
+ }
} catch(const theory::Interrupted&) {
Trace("theory") << "TheoryEngine::check() => interrupted" << endl;
@@ -381,7 +408,7 @@ Debug("theory") << "done<" << THEORY << ">" << std::endl; \
void TheoryEngine::combineTheories() {
- Debug("sharing") << "TheoryEngine::combineTheories()" << std::endl;
+ Debug("sharing") << "TheoryEngine::combineTheories()" << endl;
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
@@ -399,7 +426,7 @@ void TheoryEngine::combineTheories() {
// Call on each parametric theory to give us its care graph
CVC4_FOR_EACH_THEORY;
- Debug("sharing") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << std::endl;
+ Debug("sharing") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl;
// Now add splitters for the ones we are interested in
CareGraph::const_iterator care_it = careGraph.begin();
@@ -407,47 +434,17 @@ void TheoryEngine::combineTheories() {
for (; care_it != care_it_end; ++ care_it) {
const CarePair& carePair = *care_it;
- Debug("sharing") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << std::endl;
+ Debug("sharing") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl;
Assert(d_sharedTerms.isShared(carePair.a) || carePair.a.isConst());
Assert(d_sharedTerms.isShared(carePair.b) || carePair.b.isConst());
- //AJR-temp Assert(!d_sharedTerms.areEqual(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
- //AJR-temp Assert(!d_sharedTerms.areDisequal(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
- // The equality in question
- Node equality = carePair.a < carePair.b ?
- carePair.a.eqNode(carePair.b) :
- carePair.b.eqNode(carePair.a);
-
- // Normalize the equality
- Node normalizedEquality = Rewriter::rewrite(equality);
-
- // Check if the normalized equality already has a value (this also
- // covers constants, since they always have values
- if (d_propEngine->isSatLiteral(normalizedEquality)) {
- bool value;
- if (d_propEngine->hasValue(normalizedEquality, value)) {
- Assert(equality != normalizedEquality);
- Node literal = value ? equality : equality.notNode();
- Node normalizedLiteral = value ? normalizedEquality : normalizedEquality.notNode();
- // We're sending the original literal back, backed by the normalized one
- if (markPropagation(literal, normalizedLiteral, /* to */ carePair.theory, /* from */ THEORY_SAT_SOLVER)) {
- // We assert it, and we know it's preregistereed if it's the same theory
- bool preregistered = Theory::theoryOf(literal) == carePair.theory;
- theoryOf(carePair.theory)->assertFact(literal, preregistered);
- // Mark that we have more information
- d_factsAsserted = true;
- continue;
- } else {
- Message() << "mark propagation fail: " << literal << " " << normalizedLiteral << " " << carePair.theory << std::endl;
- Unreachable();
- }
- }
- }
+ // The equality in question (order for no repetition)
+ Node equality = carePair.a.eqNode(carePair.b);
// We need to split on it
- Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << std::endl;
- lemma(equality.orNode(equality.notNode()), false, false);
+ Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << endl;
+ lemma(equality.orNode(equality.notNode()), false, false, carePair.theory);
}
}
@@ -471,15 +468,19 @@ void TheoryEngine::propagate(Theory::Effort effort) {
CVC4_FOR_EACH_THEORY;
if(Dump.isOn("missed-t-propagations")) {
- for(unsigned i = 0; i < d_possiblePropagations.size(); ++ i) {
+ for(unsigned i = 0; i < d_possiblePropagations.size(); ++i) {
Node atom = d_possiblePropagations[i];
bool value;
- if (!d_propEngine->hasValue(atom, value)) continue;
+ if(d_propEngine->hasValue(atom, value)) {
+ continue;
+ }
// Doesn't have a value, check it (and the negation)
if(d_hasPropagated.find(atom) == d_hasPropagated.end()) {
Dump("missed-t-propagations")
<< CommentCommand("Completeness check for T-propagations; expect invalid")
+ << EchoCommand(atom.toString())
<< QueryCommand(atom.toExpr())
+ << EchoCommand(atom.notNode().toString())
<< QueryCommand(atom.notNode().toExpr());
}
}
@@ -600,12 +601,12 @@ void TheoryEngine::collectModelInfo( theory::TheoryModel* m, bool fullModel ){
/* get model */
TheoryModel* TheoryEngine::getModel() {
- Debug("model") << "TheoryEngine::getModel()" << std::endl;
+ Debug("model") << "TheoryEngine::getModel()" << endl;
if( d_logicInfo.isQuantified() ) {
- Debug("model") << "Get model from quantifiers engine." << std::endl;
+ Debug("model") << "Get model from quantifiers engine." << endl;
return d_quantEngine->getModel();
} else {
- Debug("model") << "Get default model." << std::endl;
+ Debug("model") << "Get default model." << endl;
return d_curr_model;
}
}
@@ -879,11 +880,11 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the
PropagationMap::const_iterator find = d_propagationMap.find(toAssert);
if (find != d_propagationMap.end()) {
// The theory already knows this
- Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << std::endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl;
return false;
}
- Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << std::endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl;
// Mark the propagation
d_propagationMap[toAssert] = toExplain;
@@ -893,9 +894,9 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the
}
-void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
+void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
- Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << std::endl;
+ Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << endl;
Assert(toTheoryId != fromTheoryId);
if(! d_logicInfo.isTheoryEnabled(toTheoryId) &&
@@ -915,6 +916,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// If sharing is disabled, things are easy
if (!d_logicInfo.isSharingEnabled()) {
+ Assert(assertion == originalAssertion);
if (fromTheoryId == THEORY_SAT_SOLVER) {
// Send to the apropriate theory
theory::Theory* toTheory = theoryOf(toTheoryId);
@@ -928,7 +930,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
bool value;
if (d_propEngine->hasValue(assertion, value)) {
if (!value) {
- Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict" << std::endl;
+ Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict" << endl;
d_inConflict = true;
} else {
return;
@@ -948,7 +950,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// If sending to the shared terms database, it's also simple
if (toTheoryId == THEORY_BUILTIN) {
Assert(atom.getKind() == kind::EQUAL, "atom should be an EQUALity, not `%s'", atom.toString().c_str());
- if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
d_sharedTerms.assertEquality(atom, polarity, assertion);
}
return;
@@ -958,9 +960,11 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// directly to the apropriate theory
if (fromTheoryId == THEORY_SAT_SOLVER) {
// We know that this is normalized, so just send it off to the theory
- if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) {
- // We assert it, and we know it's preregistereed coming from the SAT solver directly
- theoryOf(toTheoryId)->assertFact(assertion, true);
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
+ // Is it preregistered
+ bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
+ // We assert it
+ theoryOf(toTheoryId)->assertFact(assertion, preregistered);
// Mark that we have more information
d_factsAsserted = true;
}
@@ -970,7 +974,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
// Propagations to the SAT solver are just enqueued for pickup by
// the SAT solver later
if (toTheoryId == THEORY_SAT_SOLVER) {
- if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
// Enqueue for propagation to the SAT solver
d_propagatedLiterals.push_back(assertion);
// Check for propositional conflicts
@@ -982,18 +986,16 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
return;
}
- // See if it rewrites to true or false directly
+ Assert(atom.getKind() == kind::EQUAL);
+
+ // Normalize
Node normalizedLiteral = Rewriter::rewrite(assertion);
+
+ // See if it rewrites false directly -> conflict
if (normalizedLiteral.isConst()) {
- if (normalizedLiteral.getConst<bool>()) {
- // trivially true, but theories need to share even trivially true facts
- // unless of course it is the theory that normalized it
- if (Theory::theoryOf(atom) == toTheoryId) {
- return;
- }
- } else {
+ if (!normalizedLiteral.getConst<bool>()) {
// Mark the propagation for explanations
- if (markPropagation(normalizedLiteral, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(normalizedLiteral, originalAssertion, toTheoryId, fromTheoryId)) {
// Get the explanation (conflict will figure out where it came from)
conflict(normalizedLiteral, toTheoryId);
} else {
@@ -1003,25 +1005,12 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
}
}
- // Normalize to lhs < rhs if not a sat literal
- Assert(atom.getKind() == kind::EQUAL);
- Assert(atom[0] != atom[1]);
-
- Node normalizedAtom = atom;
- if (!d_propEngine->isSatLiteral(normalizedAtom)) {
- Node reverse = atom[1].eqNode(atom[0]);
- if (d_propEngine->isSatLiteral(reverse) || atom[0] > atom[1]) {
- normalizedAtom = reverse;
- }
- }
- Node normalizedAssertion = polarity ? normalizedAtom : normalizedAtom.notNode();
-
// Try and assert (note that we assert the non-normalized one)
- if (markPropagation(normalizedAssertion, assertion, toTheoryId, fromTheoryId)) {
+ if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
// Check if has been pre-registered with the theory
- bool preregistered = d_propEngine->isSatLiteral(normalizedAssertion) && Theory::theoryOf(normalizedAtom) == toTheoryId;
+ bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
// Assert away
- theoryOf(toTheoryId)->assertFact(normalizedAssertion, preregistered);
+ theoryOf(toTheoryId)->assertFact(assertion, preregistered);
d_factsAsserted = true;
}
@@ -1030,7 +1019,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId,
void TheoryEngine::assertFact(TNode literal)
{
- Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << std::endl;
+ Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl;
d_propEngine->checkTime();
@@ -1067,22 +1056,33 @@ void TheoryEngine::assertFact(TNode literal)
// to the assert the equality to the interested theories
if (atom.getKind() == kind::EQUAL) {
// Assert it to the the owning theory
- assertToTheory(literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
// Shared terms manager will assert to interested theories directly, as the terms become shared
- assertToTheory(literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
+
+ // Now, let's check for any atom triggers from lemmas
+ AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom);
+ while (!it.done()) {
+ const AtomRequests::Request& request = it.get();
+ Node toAssert = polarity ? (Node) request.atom : request.atom.notNode();
+ Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal << "): sending requested " << toAssert << endl;
+ assertToTheory(toAssert, literal, request.toTheory, THEORY_SAT_SOLVER);
+ it.next();
+ }
+
} else {
// Not an equality, just assert to the appropriate theory
- assertToTheory(literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
}
} else {
// Assert the fact to the appropriate theory directly
- assertToTheory(literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
+ assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
}
}
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
- Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << std::endl;
+ Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl;
d_propEngine->checkTime();
@@ -1101,16 +1101,16 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) {
if (d_propEngine->isSatLiteral(literal)) {
// We propagate SAT literals to SAT
- assertToTheory(literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
+ assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
}
if (theory != THEORY_BUILTIN) {
// Assert to the shared terms database
- assertToTheory(literal, /* to */ THEORY_BUILTIN, /* from */ theory);
+ assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
}
} else {
// Just send off to the SAT solver
Assert(d_propEngine->isSatLiteral(literal));
- assertToTheory(literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
+ assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
}
return !d_inConflict;
@@ -1166,7 +1166,7 @@ static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
Node TheoryEngine::getExplanation(TNode node) {
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
bool polarity = node.getKind() != kind::NOT;
TNode atom = polarity ? node : node[0];
@@ -1174,7 +1174,7 @@ Node TheoryEngine::getExplanation(TNode node) {
// If we're not in shared mode, explanations are simple
if (!d_logicInfo.isSharingEnabled()) {
Node explanation = theoryOf(atom)->explain(node);
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
return explanation;
}
@@ -1188,12 +1188,115 @@ Node TheoryEngine::getExplanation(TNode node) {
getExplanation(explanationVector);
Node explanation = mkExplanation(explanationVector);
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
return explanation;
}
-theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable) {
+struct AtomsCollect {
+
+ std::vector<TNode> d_atoms;
+ std::hash_set<TNode, TNodeHashFunction> d_visited;
+
+public:
+
+ typedef void return_type;
+
+ bool alreadyVisited(TNode current, TNode parent) {
+ // Check if already visited
+ d_visited.find(current) != d_visited.end();
+ // Don't visit non-boolean
+ if (!current.getType().isBoolean()) return true;
+ // New node
+ return false;
+ }
+
+ void visit(TNode current, TNode parent) {
+ if (Theory::theoryOf(current) != theory::THEORY_BOOL) {
+ d_atoms.push_back(current);
+ }
+ d_visited.insert(current);
+ }
+
+ void start(TNode node) {}
+ void done(TNode node) {}
+
+ std::vector<TNode> getAtoms() const {
+ return d_atoms;
+ }
+};
+
+void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) {
+ for (unsigned i = 0; i < atoms.size(); ++ i) {
+
+ // Non-equality atoms are either owned by theory or they don't make sense
+ if (atoms[i].getKind() != kind::EQUAL) {
+ continue;
+ }
+
+ // The equality
+ Node eq = atoms[i];
+ // Simple normalization to not repeat stuff
+ if (eq[0] > eq[1]) {
+ eq = eq[1].eqNode(eq[0]);
+ }
+
+ // Rewrite the equality
+ Node eqNormalized = Rewriter::rewrite(atoms[i]);
+
+ Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq << " with nf " << eqNormalized << endl;
+
+ // If the equality is a boolean constant, we send immediately
+ if (eqNormalized.isConst()) {
+ if (eqNormalized.getConst<bool>()) {
+ assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
+ } else {
+ assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
+ }
+ continue;
+ }
+
+ Assert(eqNormalized.getKind() == kind::EQUAL);
+
+
+ // If the normalization did the just flips, keep the flip
+ if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) {
+ eq = eqNormalized;
+ }
+
+ // Check if the equality is already known by the sat solver
+ if (d_propEngine->isSatLiteral(eqNormalized)) {
+ bool value;
+ if (d_propEngine->hasValue(eqNormalized, value)) {
+ if (value) {
+ assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER);
+ continue;
+ } else {
+ assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER);
+ continue;
+ }
+ }
+ }
+
+ // If the theory is asking about a different form, or the form is ok but if will go to a different theory
+ // then we must figure it out
+ if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) {
+ // If you get eqNormalized, send atoms[i] to atomsTo
+ d_atomRequests.add(eqNormalized, eq, atomsTo);
+ }
+ }
+}
+
+theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable, theory::TheoryId atomsTo) {
+
+ // Do we need to check atoms
+ if (atomsTo != theory::THEORY_LAST) {
+ Debug("theory::atoms") << "TheoryEngine::lemma(" << node << ", " << atomsTo << ")" << endl;
+ AtomsCollect collectAtoms;
+ NodeVisitor<AtomsCollect>::run(collectAtoms, node);
+ ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo);
+ }
+
if(Dump.isOn("t-lemmas")) {
Node n = node;
if (negated) {
@@ -1215,6 +1318,18 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
d_iteRemover.run(additionalLemmas, iteSkolemMap);
additionalLemmas[0] = theory::Rewriter::rewrite(additionalLemmas[0]);
+ if(Debug.isOn("lemma-ites")) {
+ Debug("lemma-ites") << "removed ITEs from lemma: " << node << endl;
+ Debug("lemma-ites") << " + now have the following "
+ << additionalLemmas.size() << " lemma(s):" << endl;
+ for(std::vector<Node>::const_iterator i = additionalLemmas.begin();
+ i != additionalLemmas.end();
+ ++i) {
+ Debug("lemma-ites") << " + " << *i << endl;
+ }
+ Debug("lemma-ites") << endl;
+ }
+
// assert to prop engine
d_propEngine->assertLemma(additionalLemmas[0], negated, removable);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
@@ -1249,7 +1364,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
- Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << std::endl;
+ Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << endl;
// Mark that we are in conflict
d_inConflict = true;
@@ -1267,13 +1382,13 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
// Process the explanation
getExplanation(explanationVector);
Node fullConflict = mkExplanation(explanationVector);
- Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << std::endl;
+ Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
- lemma(fullConflict, true, true);
+ lemma(fullConflict, true, true, THEORY_LAST);
} else {
// When only one theory, the conflict should need no processing
Assert(properConflict(conflict));
- lemma(conflict, true, true);
+ lemma(conflict, true, true, THEORY_LAST);
}
}
@@ -1301,9 +1416,9 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// Get the current literal to explain
NodeTheoryPair toExplain = explanationVector[i];
- Debug("theory::explain") << "TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << std::endl;
+ Debug("theory::explain") << "TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
- // If a treu constant or a negation of a false constant we can ignore it
+ // If a true constant or a negation of a false constant we can ignore it
if (toExplain.node.isConst() && toExplain.node.getConst<bool>()) {
++ i;
continue;
@@ -1321,7 +1436,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
// If an and, expand it
if (toExplain.node.getKind() == kind::AND) {
- Debug("theory::explain") << "TheoryEngine::explain(): expanding " << toExplain.node << " got from " << toExplain.theory << std::endl;
+ Debug("theory::explain") << "TheoryEngine::explain(): expanding " << toExplain.node << " got from " << toExplain.theory << endl;
for (unsigned k = 0; k < toExplain.node.getNumChildren(); ++ k) {
NodeTheoryPair newExplain(toExplain.node[k], toExplain.theory, toExplain.timestamp);
explanationVector.push_back(newExplain);
@@ -1348,7 +1463,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
} else {
explanation = theoryOf(toExplain.theory)->explain(toExplain.node);
}
- Debug("theory::explain") << "TheoryEngine::explain(): got explanation " << explanation << " got from " << toExplain.theory << std::endl;
+ Debug("theory::explain") << "TheoryEngine::explain(): got explanation " << explanation << " got from " << toExplain.theory << endl;
Assert(explanation != toExplain.node, "wasn't sent to you, so why are you explaining it trivially");
// Mark the explanation
NodeTheoryPair newExplain(explanation, toExplain.theory, toExplain.timestamp);
@@ -1368,7 +1483,7 @@ void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
void TheoryEngine::setUserAttribute(const std::string& attr, Node n) {
- Trace("te-attr") << "set user attribute " << attr << " " << n << std::endl;
+ Trace("te-attr") << "set user attribute " << attr << " " << n << endl;
if( d_attr_handle.find( attr )!=d_attr_handle.end() ){
for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){
d_attr_handle[attr][i]->setUserAttribute(attr, n);
@@ -1379,7 +1494,7 @@ void TheoryEngine::setUserAttribute(const std::string& attr, Node n) {
}
void TheoryEngine::handleUserAttribute(const char* attr, Theory* t) {
- Trace("te-attr") << "Handle user attribute " << attr << " " << t << std::endl;
+ Trace("te-attr") << "Handle user attribute " << attr << " " << t << endl;
std::string str( attr );
d_attr_handle[ str ].push_back( t );
}
@@ -1395,7 +1510,13 @@ void TheoryEngine::checkTheoryAssertionsWithModel() {
++it) {
Node assertion = (*it).assertion;
Node val = getModel()->getValue(assertion);
- Assert(val == d_true);
+ if(val != d_true) {
+ stringstream ss;
+ ss << theoryId << " has an asserted fact that the model doesn't satisfy." << endl
+ << "The fact: " << assertion << endl
+ << "Model value: " << val << endl;
+ InternalError(ss.str());
+ }
}
}
}
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index c21819ea1..53ff4d167 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -28,7 +28,6 @@
#include "prop/prop_engine.h"
#include "context/cdhashset.h"
#include "theory/theory.h"
-#include "theory/substitutions.h"
#include "theory/rewriter.h"
#include "theory/substitutions.h"
#include "theory/shared_terms_database.h"
@@ -46,6 +45,7 @@
#include "theory/unconstrained_simplifier.h"
#include "theory/uf/equality_engine.h"
#include "theory/bv/bv_to_bool.h"
+#include "theory/atom_requests.h"
namespace CVC4 {
@@ -75,6 +75,9 @@ struct NodeTheoryPairHashFunction {
}
};/* struct NodeTheoryPairHashFunction */
+
+
+
namespace theory {
class TheoryModel;
class TheoryEngineModelBuilder;
@@ -271,8 +274,10 @@ class TheoryEngine {
}
void safePoint() throw(theory::Interrupted, AssertionException) {
- if (d_engine->d_interrupted)
+ spendResource();
+ if (d_engine->d_interrupted) {
throw theory::Interrupted();
+ }
}
void conflict(TNode conflictNode) throw(AssertionException) {
@@ -293,7 +298,14 @@ class TheoryEngine {
Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
++ d_statistics.lemmas;
d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, false, removable);
+ return d_engine->lemma(lemma, false, removable, theory::THEORY_LAST);
+ }
+
+ theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException) {
+ Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
+ ++ d_statistics.lemmas;
+ d_engine->d_outputChannelUsed = true;
+ return d_engine->lemma(lemma, false, removable, d_theory);
}
void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException) {
@@ -329,6 +341,7 @@ class TheoryEngine {
void spendResource() throw() {
d_engine->spendResource();
}
+
void handleUserAttribute( const char* attr, theory::Theory* t ){
d_engine->handleUserAttribute( attr, t );
}
@@ -430,10 +443,20 @@ class TheoryEngine {
*/
bool d_outputChannelUsed;
+ /** Atom requests from lemmas */
+ AtomRequests d_atomRequests;
+
/**
* Adds a new lemma, returning its status.
+ * @param node the lemma
+ * @param negated should the lemma be asserted negated
+ * @param removable can the lemma be remove (restrictions apply)
+ * @param needAtoms if not THEORY_LAST, then
*/
- theory::LemmaStatus lemma(TNode node, bool negated, bool removable);
+ theory::LemmaStatus lemma(TNode node, bool negated, bool removable, theory::TheoryId atomsTo);
+
+ /** Enusre that the given atoms are send to the given theory */
+ void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
RemoveITE& d_iteRemover;
@@ -535,13 +558,18 @@ private:
context::CDO<bool> d_factsAsserted;
/**
+ * Map from equality atoms to theories that would like to be notified about them.
+ */
+
+
+ /**
* Assert the formula to the given theory.
* @param assertion the assertion to send (not necesserily normalized)
* @param original the assertion as it was sent in from the propagating theory
* @param toTheoryId the theory to assert to
* @param fromTheoryId the theory that sent it
*/
- void assertToTheory(TNode assertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId);
+ void assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId);
/**
* Marks a theory propagation from a theory to a theory where a
@@ -744,7 +772,7 @@ private:
void dumpAssertions(const char* tag);
/** For preprocessing pass simplifying ITEs */
- ITESimplifier d_iteSimplifier;
+ theory::ITESimplifier d_iteSimplifier;
/** For preprocessing pass simplifying unconstrained expressions */
UnconstrainedSimplifier d_unconstrainedSimp;
diff --git a/src/theory/theory_test_utils.h b/src/theory/theory_test_utils.h
index 237b09bc1..e4921b163 100644
--- a/src/theory/theory_test_utils.h
+++ b/src/theory/theory_test_utils.h
@@ -107,6 +107,11 @@ public:
d_callHistory.clear();
}
+ LemmaStatus splitLemma(TNode n, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException){
+ push(LEMMA, n);
+ return LemmaStatus(Node::null(), 0);
+ }
+
Node getIthNode(int i) {
Node tmp = (d_callHistory[i]).second;
return tmp;
diff --git a/src/theory/theoryof_mode.h b/src/theory/theoryof_mode.h
index cd8c68b1a..c50960257 100644
--- a/src/theory/theoryof_mode.h
+++ b/src/theory/theoryof_mode.h
@@ -14,10 +14,10 @@
** Option selection for theoryOf() operation.
**/
-#pragma once
-
#include "cvc4_public.h"
+#pragma once
+
namespace CVC4 {
namespace theory {
@@ -29,6 +29,18 @@ enum TheoryOfMode {
THEORY_OF_TERM_BASED
};/* enum TheoryOfMode */
+inline std::ostream& operator<<(std::ostream& out, TheoryOfMode m) throw() CVC4_PUBLIC;
+
+inline std::ostream& operator<<(std::ostream& out, TheoryOfMode m) throw() {
+ switch(m) {
+ case THEORY_OF_TYPE_BASED: return out << "THEORY_OF_TYPE_BASED";
+ case THEORY_OF_TERM_BASED: return out << "THEORY_OF_TERM_BASED";
+ default: return out << "TheoryOfMode!UNKNOWN";
+ }
+
+ Unreachable();
+}
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/type_enumerator.h b/src/theory/type_enumerator.h
index 7a4fcdaff..467bf1927 100644
--- a/src/theory/type_enumerator.h
+++ b/src/theory/type_enumerator.h
@@ -98,13 +98,21 @@ public:
~TypeEnumerator() { delete d_te; }
bool isFinished() throw() {
-#ifdef CVC4_ASSERTIONS
+// On Mac clang, there appears to be a code generation bug in an exception
+// block here. For now, there doesn't appear a good workaround; just disable
+// assertions on that setup.
+#if defined(CVC4_ASSERTIONS) && !(defined(__APPLE__) && defined(__clang__))
if(d_te->isFinished()) {
try {
**d_te;
Assert(false, "expected an NoMoreValuesException to be thrown");
} catch(NoMoreValuesException&) {
// ignore the exception, we're just asserting that it would be thrown
+ //
+ // This block can crash on clang 3.0 on Mac OS, perhaps related to
+ // bug: http://llvm.org/bugs/show_bug.cgi?id=13359
+ //
+ // Hence the #if !(defined(__APPLE__) && defined(__clang__)) above
}
} else {
try {
@@ -113,11 +121,14 @@ public:
Assert(false, "didn't expect a NoMoreValuesException to be thrown");
}
}
-#endif /* CVC4_ASSERTIONS */
+#endif /* CVC4_ASSERTIONS && !(APPLE || clang) */
return d_te->isFinished();
}
Node operator*() throw(NoMoreValuesException) {
-#ifdef CVC4_ASSERTIONS
+// On Mac clang, there appears to be a code generation bug in an exception
+// block above (and perhaps here, too). For now, there doesn't appear a
+// good workaround; just disable assertions on that setup.
+#if defined(CVC4_ASSERTIONS) && !(defined(__APPLE__) && defined(__clang__))
try {
Node n = **d_te;
Assert(n.isConst());
@@ -127,9 +138,9 @@ public:
Assert(isFinished());
throw;
}
-#else /* CVC4_ASSERTIONS */
+#else /* CVC4_ASSERTIONS && !(APPLE || clang) */
return **d_te;
-#endif /* CVC4_ASSERTIONS */
+#endif /* CVC4_ASSERTIONS && !(APPLE || clang) */
}
TypeEnumerator& operator++() throw() { ++*d_te; return *this; }
TypeEnumerator operator++(int) throw() { TypeEnumerator te = *this; ++*d_te; return te; }
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 7f0f79ebc..199581b98 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -1348,7 +1348,7 @@ void EqualityEngine::propagate() {
}
// If not merging internal nodes, notify the master
- if (d_masterEqualityEngine && !d_isInternal[mergeInto]) {
+ if (d_masterEqualityEngine && !d_isInternal[t1classId] && !d_isInternal[t2classId]) {
d_masterEqualityEngine->assertEqualityInternal(d_nodes[t1classId], d_nodes[t2classId], TNode::null());
d_masterEqualityEngine->propagate();
}
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 206fb61c7..8d1b6f1d9 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -211,11 +211,6 @@ public:
}
};/* struct EqualityEngine::statistics */
- /**
- * Store the application lookup, with enough information to backtrack
- */
- void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId);
-
private:
/** The context we are using */
@@ -254,6 +249,11 @@ private:
/** Number of application lookups, for backtracking. */
context::CDO<DefaultSizeType> d_applicationLookupsCount;
+ /**
+ * Store the application lookup, with enough information to backtrack
+ */
+ void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId);
+
/** Map from ids to the nodes (these need to be nodes as we pick up the operators) */
std::vector<Node> d_nodes;
@@ -741,7 +741,7 @@ public:
/**
* Adds a predicate p with given polarity. The predicate asserted
* should be in the congruence closure kinds (otherwise it's
- * useless.
+ * useless).
*
* @param p the (non-negated) predicate
* @param polarity true if asserting the predicate, false if
@@ -777,7 +777,7 @@ public:
void getUseListTerms(TNode t, std::set<TNode>& output);
/**
- * Get an explanation of the equality t1 = t2 begin true of false.
+ * Get an explanation of the equality t1 = t2 being true or false.
* Returns the reasons (added when asserting) that imply it
* in the assertions vector.
*/
diff --git a/src/theory/uf/options b/src/theory/uf/options
index 33d1255ef..b9f60b83d 100644
--- a/src/theory/uf/options
+++ b/src/theory/uf/options
@@ -8,6 +8,9 @@ module UF "theory/uf/options.h" Uninterpreted functions theory
option ufSymmetryBreaker uf-symmetry-breaker --symmetry-breaker bool :read-write :default true
use UF symmetry breaker (Deharbe et al., CADE 2011)
+option condenseFunctionValues condense-function-values --condense-function-values bool :default true
+ condense models for functions rather than explicitly representing them
+
option ufssRegions /--disable-uf-ss-regions bool :default true
disable region-based method for discovering cliques and splits in uf strong solver
option ufssEagerSplits --uf-ss-eager-split bool :default false
@@ -20,6 +23,8 @@ option ufssTotalityLimited --uf-ss-totality-limited=N int :default -1
apply totality axioms, but only up to cardinality N (-1 == do not apply totality axioms, default)
option ufssTotalityLazy --uf-ss-totality-lazy bool :default false
apply totality axioms lazily
+option ufssTotalitySymBreak --uf-ss-totality-sym-break bool :default false
+ apply symmetry breaking for totality axioms
option ufssAbortCardinality --uf-ss-abort-card=N int :default -1
tells the uf strong solver a cardinality to abort at (-1 == no limit, default)
option ufssSmartSplits --uf-ss-smart-split bool :default false
@@ -30,5 +35,12 @@ option ufssSimpleCliques --uf-ss-simple-cliques bool :default true
always use simple clique lemmas for uf strong solver
option ufssDiseqPropagation --uf-ss-deq-prop bool :default false
eagerly propagate disequalities for uf strong solver
+option ufssMinimalModel /--disable-uf-ss-min-model bool :default true
+ disable finding a minimal model in uf strong solver
+option ufssCliqueSplits --uf-ss-clique-splits bool :default false
+ use cliques instead of splitting on demand to shrink model
+
+option ufssSymBreak --uf-ss-sym-break bool :default false
+ finite model finding symmetry breaking techniques
endmodule
diff --git a/src/theory/uf/symmetry_breaker.cpp b/src/theory/uf/symmetry_breaker.cpp
index fcb6c3cd5..f5d7f9235 100644
--- a/src/theory/uf/symmetry_breaker.cpp
+++ b/src/theory/uf/symmetry_breaker.cpp
@@ -52,6 +52,8 @@ namespace CVC4 {
namespace theory {
namespace uf {
+using namespace ::CVC4::context;
+
SymmetryBreaker::Template::Template() :
d_template(),
d_sets(),
@@ -165,7 +167,10 @@ void SymmetryBreaker::Template::reset() {
d_reps.clear();
}
-SymmetryBreaker::SymmetryBreaker() :
+SymmetryBreaker::SymmetryBreaker(context::Context* context) :
+ ContextNotifyObj(context),
+ d_assertionsToRerun(context),
+ d_rerunningAssertions(false),
d_phi(),
d_phiSet(),
d_permutations(),
@@ -175,6 +180,31 @@ SymmetryBreaker::SymmetryBreaker() :
d_termEqs() {
}
+class SBGuard {
+ bool& d_ref;
+ bool d_old;
+public:
+ SBGuard(bool& b) : d_ref(b), d_old(b) {}
+ ~SBGuard() { Debug("uf") << "reset to " << d_old << std::endl; d_ref = d_old; }
+};/* class SBGuard */
+
+void SymmetryBreaker::rerunAssertionsIfNecessary() {
+ if(d_rerunningAssertions || !d_phi.empty() || d_assertionsToRerun.empty()) {
+ return;
+ }
+
+ SBGuard g(d_rerunningAssertions);
+ d_rerunningAssertions = true;
+
+ Debug("ufsymm") << "UFSYMM: rerunning assertions..." << std::endl;
+ for(CDList<Node>::const_iterator i = d_assertionsToRerun.begin();
+ i != d_assertionsToRerun.end();
+ ++i) {
+ assertFormula(*i);
+ }
+ Debug("ufsymm") << "UFSYMM: DONE rerunning assertions..." << std::endl;
+}
+
Node SymmetryBreaker::norm(TNode phi) {
Node n = Rewriter::rewrite(phi);
return normInternal(n);
@@ -254,6 +284,10 @@ Node SymmetryBreaker::normInternal(TNode n) {
}
void SymmetryBreaker::assertFormula(TNode phi) {
+ rerunAssertionsIfNecessary();
+ if(!d_rerunningAssertions) {
+ d_assertionsToRerun.push_back(phi);
+ }
// use d_phi, put into d_permutations
Debug("ufsymm") << "UFSYMM assertFormula(): phi is " << phi << endl;
d_phi.push_back(phi);
@@ -322,6 +356,7 @@ void SymmetryBreaker::clear() {
}
void SymmetryBreaker::apply(std::vector<Node>& newClauses) {
+ rerunAssertionsIfNecessary();
guessPermutations();
Debug("ufsymm") << "UFSYMM =====================================================" << endl
<< "UFSYMM have " << d_permutations.size() << " permutation sets" << endl;
diff --git a/src/theory/uf/symmetry_breaker.h b/src/theory/uf/symmetry_breaker.h
index cf54b62c2..d04da048a 100644
--- a/src/theory/uf/symmetry_breaker.h
+++ b/src/theory/uf/symmetry_breaker.h
@@ -50,13 +50,15 @@
#include "expr/node.h"
#include "expr/node_builder.h"
+#include "context/context.h"
+#include "context/cdlist.h"
#include "util/statistics_registry.h"
namespace CVC4 {
namespace theory {
namespace uf {
-class SymmetryBreaker {
+class SymmetryBreaker : public context::ContextNotifyObj {
class Template {
Node d_template;
@@ -92,6 +94,19 @@ public:
private:
+ /**
+ * This class wasn't initially built to be incremental. It should
+ * be attached to a UserContext so that it clears everything when
+ * a pop occurs. This "assertionsToRerun" is a set of assertions to
+ * feed back through assertFormula() when we started getting things
+ * again. It's not just a matter of effectiveness, but also soundness;
+ * if some assertions (still in scope) are not seen by a symmetry-breaking
+ * round, then some symmetries that don't actually exist might be broken,
+ * leading to unsound results!
+ */
+ context::CDList<Node> d_assertionsToRerun;
+ bool d_rerunningAssertions;
+
std::vector<Node> d_phi;
std::set<TNode> d_phiSet;
Permutations d_permutations;
@@ -101,6 +116,7 @@ private:
TermEqs d_termEqs;
void clear();
+ void rerunAssertionsIfNecessary();
void guessPermutations();
bool invariantByPermutations(const Permutation& p);
@@ -140,9 +156,17 @@ private:
d_initNormalizationTimer,
"theory::uf::symmetry_breaker::timers::initNormalization");
+protected:
+
+ void contextNotifyPop() {
+ Debug("ufsymm") << "UFSYMM: clearing state due to pop" << std::endl;
+ clear();
+ }
+
public:
- SymmetryBreaker();
+ SymmetryBreaker(context::Context* context);
+ ~SymmetryBreaker() throw() {}
void assertFormula(TNode phi);
void apply(std::vector<Node>& newClauses);
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 69a963360..41935984f 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -38,7 +38,8 @@ TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel&
d_conflict(c, false),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
- d_functionsTerms(c)
+ d_functionsTerms(c),
+ d_symb(u)
{
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::APPLY_UF);
diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp
index 228cfd2c4..c0d114052 100644
--- a/src/theory/uf/theory_uf_model.cpp
+++ b/src/theory/uf/theory_uf_model.cpp
@@ -17,6 +17,10 @@
#include "theory/uf/equality_engine.h"
#include "theory/uf/theory_uf.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/options.h"
+
+#include <vector>
+#include <stack>
#define RECONSIDER_FUNC_DEFAULT_VALUE
#define USE_PARTIAL_DEFAULT_VALUES
@@ -133,28 +137,60 @@ Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& inde
}
}
-Node UfModelTreeNode::getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue ){
- if( !d_data.empty() ){
+Node UfModelTreeNode::getFunctionValue(std::vector<Node>& args, int index, Node argDefaultValue, bool simplify) {
+ if(!d_data.empty()) {
Node defaultValue = argDefaultValue;
- if( d_data.find( Node::null() )!=d_data.end() ){
- defaultValue = d_data[Node::null()].getFunctionValue( args, index+1, argDefaultValue );
+ if(d_data.find(Node::null()) != d_data.end()) {
+ defaultValue = d_data[Node::null()].getFunctionValue(args, index + 1, argDefaultValue, simplify);
}
- std::vector< Node > caseArgs;
- std::map< Node, Node > caseValues;
- for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
- if( !it->first.isNull() ){
- Node val = it->second.getFunctionValue( args, index+1, defaultValue );
- caseArgs.push_back( it->first );
- caseValues[ it->first ] = val;
+
+ vector<Node> caseArgs;
+ map<Node, Node> caseValues;
+
+ for(map< Node, UfModelTreeNode>::iterator it = d_data.begin(); it != d_data.end(); ++it) {
+ if(!it->first.isNull()) {
+ Node val = it->second.getFunctionValue(args, index + 1, defaultValue, simplify);
+ caseArgs.push_back(it->first);
+ caseValues[it->first] = val;
}
}
+
+ NodeManager* nm = NodeManager::currentNM();
Node retNode = defaultValue;
- for( int i=((int)caseArgs.size()-1); i>=0; i-- ){
- retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( caseArgs[ i ] ), caseValues[ caseArgs[ i ] ], retNode );
+
+ if(!simplify) {
+ // "non-simplifying" mode - expand function values to things like:
+ // IF (x=0 AND y=0 AND z=0) THEN value1
+ // ELSE IF (x=0 AND y=0 AND z=1) THEN value2
+ // [...etc...]
+ for(int i = (int)caseArgs.size() - 1; i >= 0; --i) {
+ Node val = caseValues[ caseArgs[ i ] ];
+ if(val.getKind() == ITE) {
+ // use a stack to reverse the order, since we're traversing outside-in
+ stack<TNode> stk;
+ do {
+ stk.push(val);
+ val = val[2];
+ } while(val.getKind() == ITE);
+ AlwaysAssert(val == defaultValue, "default values don't match when constructing function definition!");
+ while(!stk.empty()) {
+ val = stk.top();
+ stk.pop();
+ retNode = nm->mkNode(ITE, nm->mkNode(AND, args[index].eqNode(caseArgs[i]), val[0]), val[1], retNode);
+ }
+ } else {
+ retNode = nm->mkNode(ITE, args[index].eqNode(caseArgs[i]), caseValues[caseArgs[i]], retNode);
+ }
+ }
+ } else {
+ // "simplifying" mode - condense function values
+ for(int i = (int)caseArgs.size() - 1; i >= 0; --i) {
+ retNode = nm->mkNode(ITE, args[index].eqNode(caseArgs[i]), caseValues[caseArgs[i]], retNode);
+ }
}
return retNode;
- }else{
- Assert( !d_value.isNull() );
+ } else {
+ Assert(!d_value.isNull());
return d_value;
}
}
@@ -259,14 +295,16 @@ void UfModelTreeNode::debugPrint( std::ostream& out, TheoryModel* m, std::vector
}
}
-Node UfModelTree::getFunctionValue( std::vector< Node >& args ){
- Node body = d_tree.getFunctionValue( args, 0, Node::null() );
- body = Rewriter::rewrite( body );
+Node UfModelTree::getFunctionValue( std::vector< Node >& args, bool simplify ){
+ Node body = d_tree.getFunctionValue( args, 0, Node::null(), simplify );
+ if(simplify) {
+ body = Rewriter::rewrite( body );
+ }
Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args);
return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, body);
}
-Node UfModelTree::getFunctionValue( const char* argPrefix ){
+Node UfModelTree::getFunctionValue( const char* argPrefix, bool simplify ){
TypeNode type = d_op.getType();
std::vector< Node > vars;
for( size_t i=0; i<type.getNumChildren()-1; i++ ){
@@ -274,7 +312,7 @@ Node UfModelTree::getFunctionValue( const char* argPrefix ){
ss << argPrefix << (i+1);
vars.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] ) );
}
- return getFunctionValue( vars );
+ return getFunctionValue( vars, simplify );
}
Node UfModelTreeGenerator::getIntersection( TheoryModel* m, Node n1, Node n2, bool& isGround ){
@@ -309,19 +347,21 @@ void UfModelTreeGenerator::setValue( TheoryModel* m, Node n, Node v, bool ground
if( !ground ){
int defSize = (int)d_defaults.size();
for( int i=0; i<defSize; i++ ){
- bool isGround;
//for soundness, to allow variable order-independent function interpretations,
// we must ensure that the intersection of all default terms
// is also defined.
//for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
// then we must define f( b, a ).
- Node ni = getIntersection( m, n, d_defaults[i], isGround );
- if( !ni.isNull() ){
- //if the intersection exists, and is not already defined
- if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
- d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
- //use the current value
- setValue( m, ni, v, isGround, false );
+ if (!options::fmfFullModelCheck()) {
+ bool isGround;
+ Node ni = getIntersection( m, n, d_defaults[i], isGround );
+ if( !ni.isNull() ){
+ //if the intersection exists, and is not already defined
+ if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
+ d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
+ //use the current value
+ setValue( m, ni, v, isGround, false );
+ }
}
}
}
diff --git a/src/theory/uf/theory_uf_model.h b/src/theory/uf/theory_uf_model.h
index 12c1cf244..133cd2cf2 100644
--- a/src/theory/uf/theory_uf_model.h
+++ b/src/theory/uf/theory_uf_model.h
@@ -46,7 +46,7 @@ public:
/** getConstant Value function */
Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex );
/** getFunctionValue */
- Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue );
+ Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue, bool simplify = true );
/** update function */
void update( TheoryModel* m );
/** simplify function */
@@ -125,9 +125,9 @@ public:
/** getFunctionValue
* Returns a representation of this function.
*/
- Node getFunctionValue( std::vector< Node >& args );
+ Node getFunctionValue( std::vector< Node >& args, bool simplify = true );
/** getFunctionValue for args with set prefix */
- Node getFunctionValue( const char* argPrefix );
+ Node getFunctionValue( const char* argPrefix, bool simplify = true );
/** update
* This will update all values in the tree to be representatives in m.
*/
@@ -144,18 +144,12 @@ public:
void debugPrint( std::ostream& out, TheoryModel* m, int ind = 0 ){
d_tree.debugPrint( out, m, d_index_order, ind );
}
-private:
- //helper for to ITE function.
- static Node toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode );
-public:
- /** to ITE function for function model nodes */
- static Node toIte( Node fm_node, std::vector< Node >& args ) { return toIte2( fm_node, args, 0, Node::null() ); }
- static Node toIte( TypeNode type, Node fm_node, const char* argPrefix );
};
+
class UfModelTreeGenerator
{
-private:
+public:
//store for set values
Node d_default_value;
std::map< Node, Node > d_set_values[2][2];
diff --git a/src/theory/uf/theory_uf_rewriter.h b/src/theory/uf/theory_uf_rewriter.h
index 94ab47d23..40713fa41 100644
--- a/src/theory/uf/theory_uf_rewriter.h
+++ b/src/theory/uf/theory_uf_rewriter.h
@@ -21,6 +21,7 @@
#define __CVC4__THEORY__UF__THEORY_UF_REWRITER_H
#include "theory/rewriter.h"
+#include "theory/substitutions.h"
namespace CVC4 {
namespace theory {
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index d64f7df60..163dd3c1f 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -20,6 +20,8 @@
#include "theory/quantifiers/term_database.h"
#include "theory/uf/options.h"
#include "theory/model.h"
+#include "theory/quantifiers/symmetry_breaking.h"
+
//#define ONE_SPLIT_REGION
//#define DISABLE_QUICK_CLIQUE_CHECKS
@@ -117,6 +119,9 @@ void StrongSolverTheoryUF::SortModel::Region::setEqual( Node a, Node b ){
if( options::ufssDiseqPropagation() ){
d_cf->d_thss->getDisequalityPropagator()->assertDisequal(a, n, Node::null());
}
+ if( options::ufssSymBreak() ){
+ d_cf->d_thss->getSymmetryBreaker()->assertDisequal( a, n );
+ }
}
setDisequal( b, n, t, false );
nr->setDisequal( n, b, t, false );
@@ -322,6 +327,20 @@ bool StrongSolverTheoryUF::SortModel::Region::check( Theory::Effort level, int c
return false;
}
+bool StrongSolverTheoryUF::SortModel::Region::getCandidateClique( int cardinality, std::vector< Node >& clique ) {
+ if( d_testCliqueSize>=long(cardinality+1) ){
+ //test clique is a clique
+ for( NodeBoolMap::iterator it = d_testClique.begin(); it != d_testClique.end(); ++it ){
+ if( (*it).second ){
+ clique.push_back( (*it).first );
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
void StrongSolverTheoryUF::SortModel::Region::getRepresentatives( std::vector< Node >& reps ){
for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
RegionNodeInfo* rni = it->second;
@@ -394,9 +413,9 @@ void StrongSolverTheoryUF::SortModel::Region::debugPrint( const char* c, bool in
-StrongSolverTheoryUF::SortModel::SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss ) : d_type( n.getType() ),
+StrongSolverTheoryUF::SortModel::SortModel( Node n, context::Context* c, context::UserContext* u, StrongSolverTheoryUF* thss ) : d_type( n.getType() ),
d_thss( thss ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ),
- d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( 0 ),
+ d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( u, 0 ),
d_cardinality_assertions( c ), d_hasCard( c, false ){
d_cardinality_term = n;
}
@@ -501,9 +520,14 @@ void StrongSolverTheoryUF::SortModel::merge( Node a, Node b ){
}
d_reps = d_reps - 1;
- if( options::ufssDiseqPropagation() && !d_conflict ){
- //notify the disequality propagator
- d_thss->getDisequalityPropagator()->merge(a, b);
+ if( !d_conflict ){
+ if( options::ufssDiseqPropagation() ){
+ //notify the disequality propagator
+ d_thss->getDisequalityPropagator()->merge(a, b);
+ }
+ if( options::ufssSymBreak() ){
+ d_thss->getSymmetryBreaker()->merge(a, b);
+ }
}
}
}
@@ -551,9 +575,14 @@ void StrongSolverTheoryUF::SortModel::assertDisequal( Node a, Node b, Node reaso
checkRegion( bi );
}
- if( options::ufssDiseqPropagation() && !d_conflict ){
- //notify the disequality propagator
- d_thss->getDisequalityPropagator()->assertDisequal(a, b, Node::null());
+ if( !d_conflict ){
+ if( options::ufssDiseqPropagation() ){
+ //notify the disequality propagator
+ d_thss->getDisequalityPropagator()->assertDisequal(a, b, Node::null());
+ }
+ if( options::ufssSymBreak() ){
+ d_thss->getSymmetryBreaker()->assertDisequal(a, b);
+ }
}
}
}
@@ -595,9 +624,11 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
if( d_regions[i]->d_valid ){
std::vector< Node > clique;
if( d_regions[i]->check( level, d_cardinality, clique ) ){
- //add clique lemma
- addCliqueLemma( clique, out );
- return;
+ if( options::ufssMinimalModel() ){
+ //add clique lemma
+ addCliqueLemma( clique, out );
+ return;
+ }
}else{
Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
}
@@ -623,11 +654,21 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
//see if we have any recommended splits from large regions
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid && d_regions[i]->getNumReps()>d_cardinality ){
- if( addSplit( d_regions[i], out ) ){
- addedLemma = true;
+ //just add the clique lemma
+ if( level==Theory::EFFORT_FULL && options::ufssCliqueSplits() ){
+ std::vector< Node > clique;
+ if( d_regions[i]->getCandidateClique( d_cardinality, clique ) ){
+ //add clique lemma
+ addCliqueLemma( clique, out );
+ return;
+ }
+ }else{
+ if( addSplit( d_regions[i], out ) ){
+ addedLemma = true;
#ifdef ONE_SPLIT_REGION
- break;
+ break;
#endif
+ }
}
}
}
@@ -644,7 +685,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid ){
Node op = d_regions[i]->d_nodes.begin()->first;
- int sort_id = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId(op);
+ int sort_id = d_thss->getSortInference()->getSortId(op);
if( sortsFound.find( sort_id )!=sortsFound.end() ){
combineRegions( sortsFound[sort_id], i );
recheck = true;
@@ -659,13 +700,17 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
//naive strategy, force region combination involving the first valid region
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid ){
- forceCombineRegion( i, false );
- recheck = true;
- break;
+ int fcr = forceCombineRegion( i, false );
+ Trace("uf-ss-debug") << "Combined regions " << i << " " << fcr << std::endl;
+ if( options::ufssMinimalModel() || fcr!=-1 ){
+ recheck = true;
+ break;
+ }
}
}
}
if( recheck ){
+ Trace("uf-ss-debug") << "Must recheck." << std::endl;
check( level, out );
}
}
@@ -869,8 +914,10 @@ void StrongSolverTheoryUF::SortModel::checkRegion( int ri, bool checkCombine ){
//now check if region is in conflict
std::vector< Node > clique;
if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
- //explain clique
- addCliqueLemma( clique, &d_thss->getOutputChannel() );
+ if( options::ufssMinimalModel() ){
+ //explain clique
+ addCliqueLemma( clique, &d_thss->getOutputChannel() );
+ }
}
}
}
@@ -947,18 +994,33 @@ void StrongSolverTheoryUF::SortModel::moveNode( Node n, int ri ){
void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
if( d_aloc_cardinality>0 ){
Trace("uf-ss-fmf") << "No model of size " << d_aloc_cardinality << " exists for type " << d_type << " in this branch" << std::endl;
- if( Trace.isOn("uf-ss-cliques") ){
- Trace("uf-ss-cliques") << "Cliques of size " << (d_aloc_cardinality+1) << " : " << std::endl;
- for( size_t i=0; i<d_cliques[ d_aloc_cardinality ].size(); i++ ){
- Trace("uf-ss-cliques") << " ";
- for( size_t j=0; j<d_cliques[ d_aloc_cardinality ][i].size(); j++ ){
- Trace("uf-ss-cliques") << d_cliques[ d_aloc_cardinality ][i][j] << " ";
- }
- Trace("uf-ss-cliques") << std::endl;
+ }
+ if( Trace.isOn("uf-ss-cliques") ){
+ Trace("uf-ss-cliques") << "Cliques of size " << (d_aloc_cardinality+1) << " for " << d_type << " : " << std::endl;
+ for( size_t i=0; i<d_cliques[ d_aloc_cardinality ].size(); i++ ){
+ Trace("uf-ss-cliques") << " ";
+ for( size_t j=0; j<d_cliques[ d_aloc_cardinality ][i].size(); j++ ){
+ Trace("uf-ss-cliques") << d_cliques[ d_aloc_cardinality ][i][j] << " ";
}
+ Trace("uf-ss-cliques") << std::endl;
+ }
+ }
+ /*
+ if( options::ufssSymBreak() ){
+ std::vector< Node > reps;
+ getRepresentatives( reps );
+ if( d_aloc_cardinality>0 ){
+ d_thss->getSymmetryBreaker()->allocateCardinality( out, d_type, d_aloc_cardinality+1, d_cliques[ d_aloc_cardinality ], reps );
+ }else{
+ std::vector< Node > clique;
+ clique.push_back( d_cardinality_term );
+ std::vector< std::vector< Node > > cliques;
+ cliques.push_back( clique );
+ d_thss->getSymmetryBreaker()->allocateCardinality( out, d_type, 1, cliques, reps );
}
}
- d_aloc_cardinality++;
+ */
+ d_aloc_cardinality = d_aloc_cardinality + 1;
//check for abort case
if( options::ufssAbortCardinality()==d_aloc_cardinality ){
@@ -969,7 +1031,7 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
if( applyTotality( d_aloc_cardinality ) ){
//must generate new cardinality lemma term
Node var;
- if( d_aloc_cardinality==1 ){
+ if( d_aloc_cardinality==1 && !options::ufssTotalitySymBreak() ){
//get arbitrary ground term
var = d_cardinality_term;
}else{
@@ -1013,8 +1075,8 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
}
bool StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
+ Node s;
if( r->hasSplits() ){
- Node s;
if( !options::ufssSmartSplits() ){
//take the first split you find
for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
@@ -1038,13 +1100,31 @@ bool StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
}
}
}
+ Assert( s!=Node::null() );
+ }else{
+ if( !options::ufssMinimalModel() ){
+ //since candidate clique is not reported, we may need to find splits manually
+ for ( std::map< Node, Region::RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){
+ if ( it->second->d_valid ){
+ for ( std::map< Node, Region::RegionNodeInfo* >::iterator it2 = r->d_nodes.begin(); it2 != r->d_nodes.end(); ++it2 ){
+ if ( it->second!=it2->second && it2->second->d_valid ){
+ if( !r->isDisequal( it->first, it2->first, 1 ) ){
+ s = NodeManager::currentNM()->mkNode( EQUAL, it->first, it2->first );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!s.isNull() ){
//add lemma to output channel
- Assert( s!=Node::null() && s.getKind()==EQUAL );
+ Assert( s.getKind()==EQUAL );
s = Rewriter::rewrite( s );
Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
if( options::sortInference()) {
for( int i=0; i<2; i++ ){
- int si = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId( s[i] );
+ int si = d_thss->getSortInference()->getSortId( s[i] );
Trace("uf-ss-split-si") << si << " ";
}
Trace("uf-ss-split-si") << std::endl;
@@ -1071,6 +1151,12 @@ void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& cliqu
while( clique.size()>size_t(d_cardinality+1) ){
clique.pop_back();
}
+ //debugging information
+ if( options::ufssSymBreak() ){
+ std::vector< Node > clique_vec;
+ clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() );
+ addClique( d_cardinality, clique_vec );
+ }
if( options::ufssSimpleCliques() && !options::ufssExplainedCliques() ){
//add as lemma
std::vector< Node > eqs;
@@ -1083,16 +1169,10 @@ void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& cliqu
}
eqs.push_back( d_cardinality_literal[ d_cardinality ].notNode() );
Node lem = NodeManager::currentNM()->mkNode( OR, eqs );
- Trace("uf-ss-lemma") << "*** Add clique conflict " << lem << std::endl;
+ Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
++( d_thss->d_statistics.d_clique_lemmas );
out->lemma( lem );
}else{
- //debugging information
- if( Trace.isOn("uf-ss-cliques") ){
- std::vector< Node > clique_vec;
- clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() );
- d_cliques[ d_cardinality ].push_back( clique_vec );
- }
//found a clique
Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl;
Debug("uf-ss-cliques") << " ";
@@ -1217,19 +1297,49 @@ void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& cliqu
}
void StrongSolverTheoryUF::SortModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){
- Node cardLit = d_cardinality_literal[ cardinality ];
- std::vector< Node > eqs;
- for( int i=0; i<cardinality; i++ ){
- eqs.push_back( n.eqNode( getTotalityLemmaTerm( cardinality, i ) ) );
+ if( std::find( d_totality_terms[0].begin(), d_totality_terms[0].end(), n )==d_totality_terms[0].end() ){
+ if( std::find( d_totality_lems[n].begin(), d_totality_lems[n].end(), cardinality ) == d_totality_lems[n].end() ){
+ d_totality_lems[n].push_back( cardinality );
+ Node cardLit = d_cardinality_literal[ cardinality ];
+ int sort_id = 0;
+ if( options::sortInference() ){
+ sort_id = d_thss->getSortInference()->getSortId(n);
+ }
+ Trace("uf-ss-totality") << "Add totality lemma for " << n << " " << cardinality << ", sort id is " << sort_id << std::endl;
+ int use_cardinality = cardinality;
+ if( options::ufssTotalitySymBreak() ){
+ if( d_sym_break_index.find(n)!=d_sym_break_index.end() ){
+ use_cardinality = d_sym_break_index[n];
+ }else if( (int)d_sym_break_terms[n.getType()][sort_id].size()<cardinality-1 ){
+ use_cardinality = d_sym_break_terms[n.getType()][sort_id].size() + 1;
+ d_sym_break_terms[n.getType()][sort_id].push_back( n );
+ d_sym_break_index[n] = use_cardinality;
+ Trace("uf-ss-totality") << "Allocate symmetry breaking term " << n << ", index = " << use_cardinality << std::endl;
+ }
+ }
+
+ std::vector< Node > eqs;
+ for( int i=0; i<use_cardinality; i++ ){
+ eqs.push_back( n.eqNode( getTotalityLemmaTerm( cardinality, i ) ) );
+ }
+ Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
+ Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax );
+ Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl;
+ //send as lemma to the output channel
+ d_thss->getOutputChannel().lemma( lem );
+ ++( d_thss->d_statistics.d_totality_lemmas );
+ }
}
- Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
- Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax );
- Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl;
- //send as lemma to the output channel
- d_thss->getOutputChannel().lemma( lem );
- ++( d_thss->d_statistics.d_totality_lemmas );
}
+void StrongSolverTheoryUF::SortModel::addClique( int c, std::vector< Node >& clique ) {
+
+ if( d_clique_trie[c].add( clique ) ){
+ d_cliques[ c ].push_back( clique );
+ }
+}
+
+
/** apply totality */
bool StrongSolverTheoryUF::SortModel::applyTotality( int cardinality ){
return options::ufssTotality() || cardinality<=options::ufssTotalityLimited();
@@ -1307,22 +1417,16 @@ int StrongSolverTheoryUF::SortModel::getNumRegions(){
}
void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){
- //if( !options::ufssColoringSat() ){
- bool foundRegion = false;
- for( int i=0; i<(int)d_regions_index; i++ ){
- //should not have multiple regions at this point
- if( foundRegion ){
- Assert( !d_regions[i]->d_valid );
- }
- if( d_regions[i]->d_valid ){
- //this is the only valid region
- d_regions[i]->getRepresentatives( reps );
- foundRegion = true;
- }
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ //should not have multiple regions at this point
+ //if( foundRegion ){
+ // Assert( !d_regions[i]->d_valid );
+ //}
+ if( d_regions[i]->d_valid ){
+ //this is the only valid region
+ d_regions[i]->getRepresentatives( reps );
}
- //}else{
- // Unimplemented("Build representatives for fmf region sat is not implemented");
- //}
+ }
}
StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) :
@@ -1343,6 +1447,15 @@ d_rep_model_init( c )
}else{
d_deq_prop = NULL;
}
+ if( options::ufssSymBreak() ){
+ d_sym_break = new SubsortSymmetryBreaker( th->getQuantifiersEngine(), c );
+ }else{
+ d_sym_break = NULL;
+ }
+}
+
+SortInference* StrongSolverTheoryUF::getSortInference() {
+ return d_th->getQuantifiersEngine()->getTheoryEngine()->getSortInference();
}
/** get default sat context */
@@ -1361,6 +1474,9 @@ void StrongSolverTheoryUF::newEqClass( Node n ){
if( c ){
Trace("uf-ss-solver") << "StrongSolverTheoryUF: New eq class " << n << " : " << n.getType() << std::endl;
c->newEqClass( n );
+ if( options::ufssSymBreak() ){
+ d_sym_break->newEqClass( n );
+ }
}
}
@@ -1467,6 +1583,10 @@ void StrongSolverTheoryUF::check( Theory::Effort level ){
break;
}
}
+ //check symmetry breaker
+ if( !d_conflict && options::ufssSymBreak() ){
+ d_sym_break->check( level );
+ }
//disambiguate terms if necessary
//if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
// Assert( d_term_amb!=NULL );
@@ -1502,7 +1622,7 @@ void StrongSolverTheoryUF::preRegisterTerm( TNode n ){
SortModel* rm = NULL;
if( tn.isSort() ){
Trace("uf-ss-register") << "Preregister sort " << tn << "." << std::endl;
- rm = new SortModel( n, d_th->getSatContext(), this );
+ rm = new SortModel( n, d_th->getSatContext(), d_th->getUserContext(), this );
}else{
/*
if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
@@ -1572,6 +1692,14 @@ int StrongSolverTheoryUF::getCardinality( Node n ) {
}
}
+int StrongSolverTheoryUF::getCardinality( TypeNode tn ) {
+ std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
+ if( it!=d_rep_model.end() && it->second ){
+ return it->second->getCardinality();
+ }
+ return -1;
+}
+
void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){
SortModel* c = getSortModel( n );
if( c ){
@@ -1626,6 +1754,7 @@ StrongSolverTheoryUF::Statistics::Statistics():
d_clique_lemmas("StrongSolverTheoryUF::Clique_Lemmas", 0),
d_split_lemmas("StrongSolverTheoryUF::Split_Lemmas", 0),
d_disamb_term_lemmas("StrongSolverTheoryUF::Disambiguate_Term_Lemmas", 0),
+ d_sym_break_lemmas("StrongSolverTheoryUF::Symmetry_Breaking_Lemmas", 0),
d_totality_lemmas("StrongSolverTheoryUF::Totality_Lemmas", 0),
d_max_model_size("StrongSolverTheoryUF::Max_Model_Size", 1)
{
@@ -1633,6 +1762,7 @@ StrongSolverTheoryUF::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_clique_lemmas);
StatisticsRegistry::registerStat(&d_split_lemmas);
StatisticsRegistry::registerStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::registerStat(&d_sym_break_lemmas);
StatisticsRegistry::registerStat(&d_totality_lemmas);
StatisticsRegistry::registerStat(&d_max_model_size);
}
@@ -1642,6 +1772,7 @@ StrongSolverTheoryUF::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_clique_lemmas);
StatisticsRegistry::unregisterStat(&d_split_lemmas);
StatisticsRegistry::unregisterStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::unregisterStat(&d_sym_break_lemmas);
StatisticsRegistry::unregisterStat(&d_totality_lemmas);
StatisticsRegistry::unregisterStat(&d_max_model_size);
}
@@ -1785,4 +1916,4 @@ DisequalityPropagator::Statistics::Statistics():
DisequalityPropagator::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(& d_propagations);
-} \ No newline at end of file
+}
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 0cc995723..8e568444b 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -26,7 +26,13 @@
#include "util/statistics_registry.h"
namespace CVC4 {
+
+class SortInference;
+
namespace theory {
+
+class SubsortSymmetryBreaker;
+
namespace uf {
class TheoryUF;
@@ -40,11 +46,14 @@ protected:
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
typedef context::CDChunkList<Node> NodeList;
typedef context::CDList<bool> BoolList;
- typedef context::CDList<bool> IntList;
typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap;
public:
/** information for incremental conflict/clique finding for a particular sort */
class SortModel {
+ private:
+ std::map< Node, std::vector< int > > d_totality_lems;
+ std::map< TypeNode, std::map< int, std::vector< Node > > > d_sym_break_terms;
+ std::map< Node, int > d_sym_break_index;
public:
/** a partition of the current equality graph for which cliques can occur internally */
class Region {
@@ -146,6 +155,8 @@ public:
public:
/** check for cliques */
bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique );
+ /** get candidate clique */
+ bool getCandidateClique( int cardinality, std::vector< Node >& clique );
//print debug
void debugPrint( const char* c, bool incClique = false );
};
@@ -196,12 +207,29 @@ public:
/** add totality axiom */
void addTotalityAxiom( Node n, int cardinality, OutputChannel* out );
private:
+ class NodeTrie {
+ std::map< Node, NodeTrie > d_children;
+ public:
+ bool add( std::vector< Node >& n, unsigned i = 0 ){
+ Assert( i<n.size() );
+ if( i==(n.size()-1) ){
+ bool ret = d_children.find( n[i] )==d_children.end();
+ d_children[n[i]].d_children.clear();
+ return ret;
+ }else{
+ return d_children[n[i]].add( n, i+1 );
+ }
+ }
+ };
+ std::map< int, NodeTrie > d_clique_trie;
+ void addClique( int c, std::vector< Node >& clique );
+ private:
/** Are we in conflict */
context::CDO<bool> d_conflict;
/** cardinality */
context::CDO< int > d_cardinality;
/** maximum allocated cardinality */
- int d_aloc_cardinality;
+ context::CDO< int > d_aloc_cardinality;
/** cardinality lemma term */
Node d_cardinality_term;
/** cardinality totality terms */
@@ -222,7 +250,7 @@ public:
/** get totality lemma terms */
Node getTotalityLemmaTerm( int cardinality, int i );
public:
- SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss );
+ SortModel( Node n, context::Context* c, context::UserContext* u, StrongSolverTheoryUF* thss );
virtual ~SortModel(){}
/** initialize */
void initialize( OutputChannel* out );
@@ -280,6 +308,8 @@ private:
TermDisambiguator* d_term_amb;
/** disequality propagator */
DisequalityPropagator* d_deq_prop;
+ /** symmetry breaking techniques */
+ SubsortSymmetryBreaker* d_sym_break;
public:
StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th);
~StrongSolverTheoryUF() {}
@@ -289,6 +319,10 @@ public:
TermDisambiguator* getTermDisambiguator() { return d_term_amb; }
/** disequality propagator */
DisequalityPropagator* getDisequalityPropagator() { return d_deq_prop; }
+ /** symmetry breaker */
+ SubsortSymmetryBreaker* getSymmetryBreaker() { return d_sym_break; }
+ /** get sort inference module */
+ SortInference* getSortInference();
/** get default sat context */
context::Context* getSatContext();
/** get default output channel */
@@ -330,8 +364,10 @@ public:
TypeNode getCardinalityType( int i ) { return d_conf_types[i]; }
/** get is in conflict */
bool isConflict() { return d_conflict; }
- /** get cardinality for sort */
+ /** get cardinality for node */
int getCardinality( Node n );
+ /** get cardinality for type */
+ int getCardinality( TypeNode tn );
/** get representatives */
void getRepresentatives( Node n, std::vector< Node >& reps );
/** minimize */
@@ -343,6 +379,7 @@ public:
IntStat d_clique_lemmas;
IntStat d_split_lemmas;
IntStat d_disamb_term_lemmas;
+ IntStat d_sym_break_lemmas;
IntStat d_totality_lemmas;
IntStat d_max_model_size;
Statistics();
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 4f93f5a61..156288600 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -39,9 +39,11 @@ libutil_la_SOURCES = \
datatype.h \
datatype.cpp \
tuple.h \
- maybe.h \
record.h \
record.cpp \
+ divisible.h \
+ divisible.cpp \
+ maybe.h \
matcher.h \
gmp_util.h \
sexpr.h \
@@ -75,6 +77,7 @@ libutil_la_SOURCES = \
ite_removal.h \
ite_removal.cpp \
node_visitor.h \
+ chain.h \
index.h \
uninterpreted_constant.h \
uninterpreted_constant.cpp \
@@ -85,7 +88,8 @@ libutil_la_SOURCES = \
util_model.h \
util_model.cpp \
sort_inference.h \
- sort_inference.cpp
+ sort_inference.cpp \
+ regexp.h
libstatistics_la_SOURCES = \
statistics_registry.h \
@@ -122,7 +126,7 @@ EXTRA_DIST = \
datatype.i \
tuple.i \
record.i \
- output.i \
+ divisible.i \
cardinality.i \
result.i \
configuration.i \
@@ -136,7 +140,8 @@ EXTRA_DIST = \
rational.i \
hash.i \
predicate.i \
- uninterpreted_constant.i
+ uninterpreted_constant.i \
+ chain.i
DISTCLEANFILES = \
integer.h.tmp \
diff --git a/src/util/bitvector.h b/src/util/bitvector.h
index 2d5d29339..04e23217b 100644
--- a/src/util/bitvector.h
+++ b/src/util/bitvector.h
@@ -396,7 +396,7 @@ struct CVC4_PUBLIC BitVectorHashFunction {
/**
* The structure representing the extraction operation for bit-vectors. The
- * operation map bit-vectors to bit-vector of size <code>high - low + 1</code>
+ * operation maps bit-vectors to bit-vector of size <code>high - low + 1</code>
* by taking the bits at indices <code>high ... low</code>
*/
struct CVC4_PUBLIC BitVectorExtract {
@@ -492,6 +492,13 @@ struct CVC4_PUBLIC BitVectorRotateRight {
operator unsigned () const { return rotateRightAmount; }
};/* struct BitVectorRotateRight */
+struct CVC4_PUBLIC IntToBitVector {
+ unsigned size;
+ IntToBitVector(unsigned size)
+ : size(size) {}
+ operator unsigned () const { return size; }
+};/* struct IntToBitVector */
+
template <typename T>
struct CVC4_PUBLIC UnsignedHashFunction {
inline size_t operator()(const T& x) const {
@@ -514,6 +521,11 @@ inline std::ostream& operator <<(std::ostream& os, const BitVectorBitOf& bv) {
return os << "[" << bv.bitIndex << "]";
}
+inline std::ostream& operator <<(std::ostream& os, const IntToBitVector& bv) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const IntToBitVector& bv) {
+ return os << "[" << bv.size << "]";
+}
+
}/* CVC4 namespace */
#endif /* __CVC4__BITVECTOR_H */
diff --git a/src/util/boolean_simplification.h b/src/util/boolean_simplification.h
index e5c4ead6c..be39f69c1 100644
--- a/src/util/boolean_simplification.h
+++ b/src/util/boolean_simplification.h
@@ -22,6 +22,7 @@
#include <vector>
#include <algorithm>
+#include "expr/expr_manager_scope.h"
#include "expr/node.h"
#include "util/cvc4_assert.h"
@@ -202,6 +203,7 @@ public:
* @param e the Expr to negate (cannot be the null Expr)
*/
static Expr negate(Expr e) throw(AssertionException) {
+ ExprManagerScope ems(e);
return negate(Node::fromExpr(e)).toExpr();
}
diff --git a/src/util/chain.h b/src/util/chain.h
new file mode 100644
index 000000000..2e9cf7bf6
--- /dev/null
+++ b/src/util/chain.h
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file chain.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "cvc4_public.h"
+
+#ifndef __CVC4__CHAIN_H
+#define __CVC4__CHAIN_H
+
+#include "expr/kind.h"
+#include <iostream>
+
+namespace CVC4 {
+
+/** A class to represent a chained, built-in operator. */
+class Chain {
+ Kind d_kind;
+public:
+ explicit Chain(Kind k) : d_kind(k) { }
+ bool operator==(const Chain& ch) const { return d_kind == ch.d_kind; }
+ bool operator!=(const Chain& ch) const { return d_kind != ch.d_kind; }
+ Kind getOperator() const { return d_kind; }
+};/* class Chain */
+
+inline std::ostream& operator<<(std::ostream& out, const Chain& ch) {
+ return out << ch.getOperator();
+}
+
+struct ChainHashFunction {
+ size_t operator()(const Chain& ch) const {
+ return kind::KindHashFunction()(ch.getOperator());
+ }
+};/* struct ChainHashFunction */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__CHAIN_H */
diff --git a/src/util/chain.i b/src/util/chain.i
new file mode 100644
index 000000000..1c97a527f
--- /dev/null
+++ b/src/util/chain.i
@@ -0,0 +1,12 @@
+%{
+#include "util/chain.h"
+%}
+
+%rename(equals) CVC4::Chain::operator==(const Chain&) const;
+%ignore CVC4::Chain::operator!=(const Chain&) const;
+
+%ignore CVC4::operator<<(std::ostream&, const Chain&);
+
+%rename(apply) CVC4::ChainHashFunction::operator()(const CVC4::Chain&) const;
+
+%include "util/chain.h"
diff --git a/src/util/cvc4_assert.cpp b/src/util/cvc4_assert.cpp
index eb7b81a39..08e2867f6 100644
--- a/src/util/cvc4_assert.cpp
+++ b/src/util/cvc4_assert.cpp
@@ -136,7 +136,7 @@ void debugAssertionFailed(const AssertionException& thisException,
const char* propagatingException) {
static CVC4_THREADLOCAL(bool) alreadyFired = false;
- if(EXPECT_TRUE( !std::uncaught_exception() ) || alreadyFired) {
+ if(__builtin_expect( ( !std::uncaught_exception() ), true ) || alreadyFired) {
throw thisException;
}
diff --git a/src/util/cvc4_assert.h b/src/util/cvc4_assert.h
index c070fc389..7d359a56b 100644
--- a/src/util/cvc4_assert.h
+++ b/src/util/cvc4_assert.h
@@ -252,7 +252,7 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
// details of the exception
# define AlwaysAssert(cond, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
/* save the last assertion failure */ \
const char* lastException = ::CVC4::s_debugLastException; \
::CVC4::AssertionException exception(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
@@ -265,7 +265,7 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
// will terminate() if thrown during stack unwinding.
# define AlwaysAssert(cond, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
throw ::CVC4::AssertionException(#cond, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
} \
} while(0)
@@ -283,13 +283,13 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
throw ::CVC4::IllegalArgumentException("", #arg, __PRETTY_FUNCTION__, ## msg)
#define CheckArgument(cond, arg, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
throw ::CVC4::IllegalArgumentException(#cond, #arg, __PRETTY_FUNCTION__, ## msg); \
} \
} while(0)
#define AlwaysAssertArgument(cond, arg, msg...) \
do { \
- if(EXPECT_FALSE( ! (cond) )) { \
+ if(__builtin_expect( ( ! (cond) ), false )) { \
throw ::CVC4::AssertArgumentException(#cond, #arg, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## msg); \
} \
} while(0)
@@ -299,9 +299,9 @@ void debugAssertionFailed(const AssertionException& thisException, const char* l
# define AssertArgument(cond, arg, msg...) AlwaysAssertArgument(cond, arg, ## msg)
# define DebugCheckArgument(cond, arg, msg...) CheckArgument(cond, arg, ## msg)
#else /* ! CVC4_ASSERTIONS */
-# define Assert(cond, msg...) /*EXPECT_TRUE( cond )*/
-# define AssertArgument(cond, arg, msg...) /*EXPECT_TRUE( cond )*/
-# define DebugCheckArgument(cond, arg, msg...) /*EXPECT_TRUE( cond )*/
+# define Assert(cond, msg...) /*__builtin_expect( ( cond ), true )*/
+# define AssertArgument(cond, arg, msg...) /*__builtin_expect( ( cond ), true )*/
+# define DebugCheckArgument(cond, arg, msg...) /*__builtin_expect( ( cond ), true )*/
#endif /* CVC4_ASSERTIONS */
}/* CVC4 namespace */
diff --git a/src/util/datatype.h b/src/util/datatype.h
index 3da441f1f..c46c10c97 100644
--- a/src/util/datatype.h
+++ b/src/util/datatype.h
@@ -33,7 +33,6 @@ namespace CVC4 {
#include "expr/expr.h"
#include "expr/type.h"
-#include "util/output.h"
#include "util/hash.h"
#include "util/exception.h"
diff --git a/src/util/debug.h b/src/util/debug.h
index 3e7c4d8be..97c176f02 100644
--- a/src/util/debug.h
+++ b/src/util/debug.h
@@ -27,11 +27,11 @@
#ifdef CVC4_ASSERTIONS
// the __builtin_expect() helps us if assert is built-in or a macro
-# define cvc4assert(x) assert(EXPECT_TRUE( x ))
+# define cvc4assert(x) assert(__builtin_expect( ( x ), true ))
#else
// TODO: use a compiler annotation when assertions are off ?
// (to improve optimization)
-# define cvc4assert(x) /*EXPECT_TRUE( x )*/
+# define cvc4assert(x) /*__builtin_expect( ( x ), true )*/
#endif /* CVC4_ASSERTIONS */
#endif /* __CVC4__DEBUG_H */
diff --git a/src/util/divisible.cpp b/src/util/divisible.cpp
new file mode 100644
index 000000000..4e20d6b5f
--- /dev/null
+++ b/src/util/divisible.cpp
@@ -0,0 +1,29 @@
+/********************* */
+/*! \file divisible.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "util/divisible.h"
+#include "util/exception.h"
+
+using namespace std;
+
+namespace CVC4 {
+
+Divisible::Divisible(const Integer& n) : k(n) {
+ CheckArgument(n > 0, n, "Divisible predicate must be constructed over positive N");
+}
+
+}/* CVC4 namespace */
diff --git a/src/util/divisible.h b/src/util/divisible.h
new file mode 100644
index 000000000..0c0c7bc5b
--- /dev/null
+++ b/src/util/divisible.h
@@ -0,0 +1,62 @@
+/********************* */
+/*! \file divisible.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "cvc4_public.h"
+
+#ifndef __CVC4__DIVISIBLE_H
+#define __CVC4__DIVISIBLE_H
+
+#include <iostream>
+#include "util/integer.h"
+#include "util/exception.h"
+
+namespace CVC4 {
+
+/**
+ * The structure representing the divisibility-by-k predicate.
+ */
+struct CVC4_PUBLIC Divisible {
+ const Integer k;
+
+ Divisible(const Integer& n);
+
+ bool operator==(const Divisible& d) const {
+ return k == d.k;
+ }
+
+ bool operator!=(const Divisible& d) const {
+ return !(*this == d);
+ }
+};/* struct Divisible */
+
+/**
+ * Hash function for the Divisible objects.
+ */
+struct CVC4_PUBLIC DivisibleHashFunction {
+ size_t operator()(const Divisible& d) const {
+ return d.k.hash();
+ }
+};/* struct DivisibleHashFunction */
+
+inline std::ostream& operator <<(std::ostream& os, const Divisible& d) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const Divisible& d) {
+ return os << "divisible-by-" << d.k;
+}
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__DIVISIBLE_H */
diff --git a/src/util/divisible.i b/src/util/divisible.i
new file mode 100644
index 000000000..7599360ca
--- /dev/null
+++ b/src/util/divisible.i
@@ -0,0 +1,10 @@
+%{
+#include "util/divisible.h"
+%}
+
+%rename(equals) CVC4::Divisible::operator==(const Divisible&) const;
+%ignore CVC4::Divisible::operator!=(const Divisible&) const;
+
+%ignore CVC4::operator<<(std::ostream&, const Divisible&);
+
+%include "util/divisible.h"
diff --git a/src/util/dump.h b/src/util/dump.h
index 2ef6010e3..0bde68d76 100644
--- a/src/util/dump.h
+++ b/src/util/dump.h
@@ -19,7 +19,6 @@
#ifndef __CVC4__DUMP_H
#define __CVC4__DUMP_H
-#include "util/output.h"
#include "expr/command.h"
namespace CVC4 {
diff --git a/src/util/exception.h b/src/util/exception.h
index 082a50ef2..cd4b763ef 100644
--- a/src/util/exception.h
+++ b/src/util/exception.h
@@ -138,13 +138,13 @@ namespace CVC4 {
#ifndef CheckArgument
template <class T> inline void CheckArgument(bool cond, const T& arg, const char* fmt, ...) CVC4_PUBLIC;
template <class T> inline void CheckArgument(bool cond, const T& arg, const char* fmt, ...) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
template <class T> inline void CheckArgument(bool cond, const T& arg) CVC4_PUBLIC;
template <class T> inline void CheckArgument(bool cond, const T& arg) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
@@ -153,13 +153,13 @@ template <class T> inline void CheckArgument(bool cond, const T& arg) {
#ifndef DebugCheckArgument
template <class T> inline void DebugCheckArgument(bool cond, const T& arg, const char* fmt, ...) CVC4_PUBLIC;
template <class T> inline void DebugCheckArgument(bool cond, const T& arg, const char* fmt, ...) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
template <class T> inline void DebugCheckArgument(bool cond, const T& arg) CVC4_PUBLIC;
template <class T> inline void DebugCheckArgument(bool cond, const T& arg) {
- if(EXPECT_FALSE( !cond )) { \
+ if(__builtin_expect( ( !cond ), false )) { \
throw ::CVC4::IllegalArgumentException("", "", ""); \
} \
}
diff --git a/src/util/ite_removal.cpp b/src/util/ite_removal.cpp
index f26bbe0aa..7d4948251 100644
--- a/src/util/ite_removal.cpp
+++ b/src/util/ite_removal.cpp
@@ -30,7 +30,11 @@ void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap)
{
for (unsigned i = 0, i_end = output.size(); i < i_end; ++ i) {
std::vector<Node> quantVar;
- output[i] = run(output[i], output, iteSkolemMap, quantVar);
+ // Do this in two steps to avoid Node problems(?)
+ // Appears related to bug 512, splitting this into two lines
+ // fixes the bug on clang on Mac OS
+ Node itesRemoved = run(output[i], output, iteSkolemMap, quantVar);
+ output[i] = itesRemoved;
}
}
diff --git a/src/util/output.h b/src/util/output.h
index 263d5a144..7394f24ab 100644
--- a/src/util/output.h
+++ b/src/util/output.h
@@ -14,7 +14,7 @@
** Output utility classes and functions.
**/
-#include "cvc4_public.h"
+#include "cvc4_private_library.h"
#ifndef __CVC4__OUTPUT_H
#define __CVC4__OUTPUT_H
diff --git a/src/util/output.i b/src/util/output.i
deleted file mode 100644
index 74953ba53..000000000
--- a/src/util/output.i
+++ /dev/null
@@ -1,70 +0,0 @@
-%{
-#include "util/output.h"
-%}
-
-%ignore CVC4::null_streambuf;
-%ignore std::streambuf;
-%feature("valuewrapper") std::ostream;
-
-// There are issues with SWIG's attempted wrapping of these variables when
-// it tries to generate the getters and setters. For now, just ignore them.
-%ignore CVC4::null_sb;
-%ignore CVC4::null_os;
-%ignore CVC4::DumpOutC::dump_cout;
-%ignore CVC4::CVC4ostream;
-
-%ignore operator<<;
-%ignore on(std::string);
-%ignore isOn(std::string);
-%ignore off(std::string);
-%ignore printf(std::string, const char*, ...);
-
-%ignore CVC4::IndentedScope;
-%ignore CVC4::push(CVC4ostream&);
-%ignore CVC4::pop(CVC4ostream&);
-
-%ignore CVC4::ScopedDebug::ScopedDebug(std::string);
-%ignore CVC4::ScopedDebug::ScopedDebug(std::string, bool);
-
-%ignore CVC4::ScopedTrace::ScopedTrace(std::string);
-%ignore CVC4::ScopedTrace::ScopedTrace(std::string, bool);
-
-%ignore CVC4::WarningC::WarningC(std::ostream*);
-%ignore CVC4::MessageC::MessageC(std::ostream*);
-%ignore CVC4::NoticeC::NoticeC(std::ostream*);
-%ignore CVC4::ChatC::ChatC(std::ostream*);
-%ignore CVC4::TraceC::TraceC(std::ostream*);
-%ignore CVC4::DebugC::DebugC(std::ostream*);
-%ignore CVC4::DumpOutC::DumpOutC(std::ostream*);
-
-%ignore CVC4::WarningC::operator();
-%ignore CVC4::MessageC::operator();
-%ignore CVC4::NoticeC::operator();
-%ignore CVC4::ChatC::operator();
-%ignore CVC4::TraceC::operator();
-%ignore CVC4::DebugC::operator();
-%ignore CVC4::DumpOutC::operator();
-
-%ignore CVC4::WarningC::getStream();
-%ignore CVC4::MessageC::getStream();
-%ignore CVC4::NoticeC::getStream();
-%ignore CVC4::ChatC::getStream();
-%ignore CVC4::TraceC::getStream();
-%ignore CVC4::DebugC::getStream();
-%ignore CVC4::DumpOutC::getStream();
-
-%ignore CVC4::WarningC::setStream(std::ostream&);
-%ignore CVC4::MessageC::setStream(std::ostream&);
-%ignore CVC4::NoticeC::setStream(std::ostream&);
-%ignore CVC4::ChatC::setStream(std::ostream&);
-%ignore CVC4::TraceC::setStream(std::ostream&);
-%ignore CVC4::DebugC::setStream(std::ostream&);
-%ignore CVC4::DumpOutC::setStream(std::ostream&);
-
-%ignore operator std::ostream&;
-%ignore operator CVC4ostream;
-
-%rename(get) operator ();
-%rename(ok) operator bool;
-
-%include "util/output.h"
diff --git a/src/util/rational_cln_imp.h b/src/util/rational_cln_imp.h
index 1e27fa859..da2af6c1f 100644
--- a/src/util/rational_cln_imp.h
+++ b/src/util/rational_cln_imp.h
@@ -155,10 +155,10 @@ public:
#ifdef CVC4_NEED_INT64_T_OVERLOADS
Rational(int64_t n, int64_t d) : d_value(static_cast<long>(n)) {
- d_value /= static_cast<long>(d);
+ d_value /= cln::cl_I(d);
}
Rational(uint64_t n, uint64_t d) : d_value(static_cast<unsigned long>(n)) {
- d_value /= static_cast<unsigned long>(d);
+ d_value /= cln::cl_I(d);
}
#endif /* CVC4_NEED_INT64_T_OVERLOADS */
diff --git a/src/util/record.h b/src/util/record.h
index 3d6481320..63c54930e 100644
--- a/src/util/record.h
+++ b/src/util/record.h
@@ -91,7 +91,6 @@ public:
Record(const std::vector< std::pair<std::string, Type> >& fields) :
d_fields(fields) {
- CheckArgument(! fields.empty(), fields, "fields in record description cannot be empty");
}
const_iterator find(std::string name) const {
diff --git a/src/util/recursion_breaker.h b/src/util/recursion_breaker.h
index 07bf10984..a4177f600 100644
--- a/src/util/recursion_breaker.h
+++ b/src/util/recursion_breaker.h
@@ -86,7 +86,7 @@ class RecursionBreaker {
static CVC4_THREADLOCAL(Map*) s_maps;
std::string d_tag;
- const T& d_item;
+ const T d_item;
bool d_firstToTag;
bool d_recursion;
diff --git a/src/util/regexp.h b/src/util/regexp.h
new file mode 100644
index 000000000..58f58a40f
--- /dev/null
+++ b/src/util/regexp.h
@@ -0,0 +1,353 @@
+/********************* */
+/*! \file regexp.h
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** 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 "cvc4_public.h"
+
+#ifndef __CVC4__REGEXP_H
+#define __CVC4__REGEXP_H
+
+#include <iostream>
+#include <string>
+//#include "util/exception.h"
+//#include "util/integer.h"
+#include "util/hash.h"
+
+namespace CVC4 {
+
+class CVC4_PUBLIC Char {
+
+private:
+ unsigned int d_char;
+
+public:
+ Char() {}
+
+ Char(const unsigned int c)
+ : d_char(c) {}
+
+ ~Char() {}
+
+ Char& operator =(const Char& y) {
+ if(this != &y) d_char = y.d_char;
+ return *this;
+ }
+
+ bool operator ==(const Char& y) const {
+ return d_char == y.d_char ;
+ }
+
+ bool operator !=(const Char& y) const {
+ return d_char != y.d_char ;
+ }
+
+ bool operator <(const Char& y) const {
+ return d_char < y.d_char;
+ }
+
+ bool operator >(const Char& y) const {
+ return d_char > y.d_char ;
+ }
+
+ bool operator <=(const Char& y) const {
+ return d_char <= y.d_char;
+ }
+
+ bool operator >=(const Char& y) const {
+ return d_char >= y.d_char ;
+ }
+
+ /*
+ * Convenience functions
+ */
+ std::string toString() const {
+ std::string str = "1";
+ str[0] = (char) d_char;
+ return str;
+ }
+
+ unsigned size() const {
+ return 1;
+ }
+
+ const char* c_str() const {
+ return toString().c_str();
+ }
+};/* class Char */
+
+namespace strings {
+
+struct CharHashFunction {
+ size_t operator()(const ::CVC4::Char& c) const {
+ return __gnu_cxx::hash<const char*>()(c.toString().c_str());
+ }
+};/* struct CharHashFunction */
+
+}
+
+inline std::ostream& operator <<(std::ostream& os, const Char& c) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const Char& c) {
+ return os << "\"" << c.toString() << "\"";
+}
+
+class CVC4_PUBLIC String {
+
+private:
+ std::vector<unsigned int> d_str;
+
+ bool isVecSame(const std::vector<unsigned int> &a, const std::vector<unsigned int> &b) const {
+ if(a.size() != b.size()) return false;
+ else {
+ for(unsigned int i=0; i<a.size(); ++i)
+ if(a[i] != b[i]) return false;
+ return true;
+ }
+ }
+
+public:
+ String() {}
+
+ String(const std::string &s) {
+ for(unsigned int i=0; i<s.size(); ++i) {
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );
+ }
+ }
+
+ String(const char* s) {
+ for(unsigned int i=0,len=strlen(s); i<len; ++i) {
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );
+ }
+ }
+
+ String(const std::vector<unsigned int> &s) : d_str(s) { }
+
+ ~String() {}
+
+ String& operator =(const String& y) {
+ if(this != &y) d_str = y.d_str;
+ return *this;
+ }
+
+ bool operator ==(const String& y) const {
+ return isVecSame(d_str, y.d_str);
+ }
+
+ bool operator !=(const String& y) const {
+ return ! ( isVecSame(d_str, y.d_str) );
+ }
+
+ 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 operator <(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() < y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] < y.d_str[i];
+
+ return false;
+ }
+ }
+
+ bool operator >(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() > y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] > y.d_str[i];
+
+ return false;
+ }
+ }
+
+ bool operator <=(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() < y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] < y.d_str[i];
+
+ return true;
+ }
+ }
+
+ bool operator >=(const String& y) const {
+ if(d_str.size() != y.d_str.size()) return d_str.size() > y.d_str.size();
+ else {
+ for(unsigned int i=0; i<d_str.size(); ++i)
+ if(d_str[i] != y.d_str[i]) return d_str[i] > y.d_str[i];
+
+ return true;
+ }
+ }
+
+ bool strncmp(const String &y, unsigned int n) const {
+ for(unsigned int i=0; i<n; ++i)
+ if(d_str[i] != y.d_str[i]) return false;
+ return true;
+ }
+
+ /*
+ * Convenience functions
+ */
+ std::string toString() const {
+ std::string str;
+ for(unsigned int i=0; i<d_str.size(); ++i) {
+ str += convertUnsignedIntToChar( d_str[i] );
+ //TODO isPrintable: ( "\\" + (convertUnsignedIntToChar( d_str[i] ) );
+ }
+ return str;
+ }
+
+ unsigned size() const {
+ return d_str.size();
+ }
+
+ String substr(unsigned i) const {
+ std::vector<unsigned int> ret_vec;
+ std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
+ //for(unsigned k=0; k<i; k++) ++itr;
+ ret_vec.insert(ret_vec.end(), itr, d_str.end());
+ return String(ret_vec);
+ }
+ String substr(unsigned i, unsigned j) const {
+ std::vector<unsigned int> ret_vec;
+ std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
+ //for(unsigned k=0; k<i; k++) ++itr;
+ //std::vector<unsigned int>::const_iterator itr2 = itr;
+ //for(unsigned k=0; k<j; k++) ++itr2;
+ ret_vec.insert( ret_vec.end(), itr, itr + j );
+ return String(ret_vec);
+ }
+
+public:
+ static unsigned int convertCharToUnsignedInt( char c ) {
+ int i = (int)c;
+ i = i-65;
+ return (unsigned int)(i<0 ? i+256 : i);
+ }
+ static char convertUnsignedIntToChar( unsigned int i ){
+ int ii = i+65;
+ return (char)(ii>=256 ? ii-256 : ii);
+ }
+ static bool isPrintable( unsigned int i ){
+ char c = convertUnsignedIntToChar( i );
+ return isprint( (int)c );
+ }
+
+};/* class String */
+
+namespace strings {
+
+struct StringHashFunction {
+ size_t operator()(const ::CVC4::String& s) const {
+ return __gnu_cxx::hash<const char*>()(s.toString().c_str());
+ }
+};/* struct StringHashFunction */
+
+}
+
+inline std::ostream& operator <<(std::ostream& os, const String& s) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const String& s) {
+ return os << "\"" << s.toString() << "\"";
+}
+
+class CVC4_PUBLIC RegExp {
+
+private:
+ std::string d_str;
+
+public:
+ RegExp() {}
+
+ RegExp(const std::string s)
+ : d_str(s) {}
+
+ ~RegExp() {}
+
+ RegExp& operator =(const RegExp& y) {
+ if(this != &y) d_str = y.d_str;
+ return *this;
+ }
+
+ bool operator ==(const RegExp& y) const {
+ return d_str == y.d_str ;
+ }
+
+ bool operator !=(const RegExp& y) const {
+ return d_str != y.d_str ;
+ }
+
+ String concat (const RegExp& other) const {
+ return String(d_str + other.d_str);
+ }
+
+ bool operator <(const RegExp& y) const {
+ return d_str < y.d_str;
+ }
+
+ bool operator >(const RegExp& y) const {
+ return d_str > y.d_str ;
+ }
+
+ bool operator <=(const RegExp& y) const {
+ return d_str <= y.d_str;
+ }
+
+ bool operator >=(const RegExp& y) const {
+ return d_str >= y.d_str ;
+ }
+
+ /*
+ * Convenience functions
+ */
+
+ size_t hash() const {
+ unsigned int h = 1;
+
+ for (size_t i = 0; i < d_str.length(); ++i) {
+ h = (h << 5) + d_str[i];
+ }
+
+ return h;
+ }
+
+ std::string toString() const {
+ return d_str;
+ }
+
+ unsigned size() const {
+ return d_str.size();
+ }
+};/* class String */
+
+/**
+ * Hash function for the RegExp constants.
+ */
+struct CVC4_PUBLIC RegExpHashFunction {
+ inline size_t operator()(const RegExp& s) const {
+ return s.hash();
+ }
+};/* struct RegExpHashFunction */
+
+inline std::ostream& operator <<(std::ostream& os, const RegExp& s) CVC4_PUBLIC;
+inline std::ostream& operator <<(std::ostream& os, const RegExp& s) {
+ return os << s.toString();
+}
+}/* CVC4 namespace */
+
+#endif /* __CVC4__STRING_H */
diff --git a/src/util/result.cpp b/src/util/result.cpp
index e0e34f07d..909a7d8c6 100644
--- a/src/util/result.cpp
+++ b/src/util/result.cpp
@@ -27,11 +27,12 @@ using namespace std;
namespace CVC4 {
-Result::Result(const std::string& instr) :
+Result::Result(const std::string& instr, std::string inputName) :
d_sat(SAT_UNKNOWN),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_NONE),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName(inputName) {
string s = instr;
transform(s.begin(), s.end(), s.begin(), ::tolower);
if(s == "sat" || s == "satisfiable") {
@@ -115,13 +116,13 @@ Result Result::asSatisfiabilityResult() const throw() {
switch(d_validity) {
case INVALID:
- return Result(SAT);
+ return Result(SAT, d_inputName);
case VALID:
- return Result(UNSAT);
+ return Result(UNSAT, d_inputName);
case VALIDITY_UNKNOWN:
- return Result(SAT_UNKNOWN, d_unknownExplanation);
+ return Result(SAT_UNKNOWN, d_unknownExplanation, d_inputName);
default:
Unhandled(d_validity);
@@ -129,7 +130,7 @@ Result Result::asSatisfiabilityResult() const throw() {
}
// TYPE_NONE
- return Result(SAT_UNKNOWN, NO_STATUS);
+ return Result(SAT_UNKNOWN, NO_STATUS, d_inputName);
}
Result Result::asValidityResult() const throw() {
@@ -141,13 +142,13 @@ Result Result::asValidityResult() const throw() {
switch(d_sat) {
case SAT:
- return Result(INVALID);
+ return Result(INVALID, d_inputName);
case UNSAT:
- return Result(VALID);
+ return Result(VALID, d_inputName);
case SAT_UNKNOWN:
- return Result(VALIDITY_UNKNOWN, d_unknownExplanation);
+ return Result(VALIDITY_UNKNOWN, d_unknownExplanation, d_inputName);
default:
Unhandled(d_sat);
@@ -155,7 +156,7 @@ Result Result::asValidityResult() const throw() {
}
// TYPE_NONE
- return Result(VALIDITY_UNKNOWN, NO_STATUS);
+ return Result(VALIDITY_UNKNOWN, NO_STATUS, d_inputName);
}
string Result::toString() const {
diff --git a/src/util/result.h b/src/util/result.h
index cb1bd50fa..21bf563bd 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -71,47 +71,58 @@ private:
enum Validity d_validity;
enum Type d_which;
enum UnknownExplanation d_unknownExplanation;
+ std::string d_inputName;
public:
Result() :
d_sat(SAT_UNKNOWN),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_NONE),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName("") {
}
- Result(enum Sat s) :
+ Result(enum Sat s, std::string inputName = "") :
d_sat(s),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_SAT),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName(inputName) {
CheckArgument(s != SAT_UNKNOWN,
"Must provide a reason for satisfiability being unknown");
}
- Result(enum Validity v) :
+ Result(enum Validity v, std::string inputName = "") :
d_sat(SAT_UNKNOWN),
d_validity(v),
d_which(TYPE_VALIDITY),
- d_unknownExplanation(UNKNOWN_REASON) {
+ d_unknownExplanation(UNKNOWN_REASON),
+ d_inputName(inputName) {
CheckArgument(v != VALIDITY_UNKNOWN,
"Must provide a reason for validity being unknown");
}
- Result(enum Sat s, enum UnknownExplanation unknownExplanation) :
+ Result(enum Sat s, enum UnknownExplanation unknownExplanation, std::string inputName = "") :
d_sat(s),
d_validity(VALIDITY_UNKNOWN),
d_which(TYPE_SAT),
- d_unknownExplanation(unknownExplanation) {
+ d_unknownExplanation(unknownExplanation),
+ d_inputName(inputName) {
CheckArgument(s == SAT_UNKNOWN,
"improper use of unknown-result constructor");
}
- Result(enum Validity v, enum UnknownExplanation unknownExplanation) :
+ Result(enum Validity v, enum UnknownExplanation unknownExplanation, std::string inputName = "") :
d_sat(SAT_UNKNOWN),
d_validity(v),
d_which(TYPE_VALIDITY),
- d_unknownExplanation(unknownExplanation) {
+ d_unknownExplanation(unknownExplanation),
+ d_inputName(inputName) {
CheckArgument(v == VALIDITY_UNKNOWN,
"improper use of unknown-result constructor");
}
- Result(const std::string& s);
+ Result(const std::string& s, std::string inputName = "");
+
+ Result(const Result& r, std::string inputName) {
+ *this = r;
+ d_inputName = inputName;
+ }
enum Sat isSat() const {
return d_which == TYPE_SAT ? d_sat : SAT_UNKNOWN;
@@ -142,6 +153,8 @@ public:
std::string toString() const;
+ std::string getInputName() const { return d_inputName; }
+
};/* class Result */
inline bool Result::operator!=(const Result& r) const throw() {
diff --git a/src/util/result.i b/src/util/result.i
index 029a3618a..b77bfd881 100644
--- a/src/util/result.i
+++ b/src/util/result.i
@@ -12,8 +12,9 @@
%ignore CVC4::operator<<(std::ostream&, enum Result::UnknownExplanation);
%ignore CVC4::operator==(enum Result::Sat, const Result&);
-%ignore CVC4::operator==(enum Result::Validity, 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&);
%include "util/result.h"
diff --git a/src/util/sort_inference.cpp b/src/util/sort_inference.cpp
index d44499fa8..b66d1cbe4 100644
--- a/src/util/sort_inference.cpp
+++ b/src/util/sort_inference.cpp
@@ -20,15 +20,70 @@
#include <vector>
#include "util/sort_inference.h"
+#include "theory/uf/options.h"
+//#include "theory/rewriter.h"
using namespace CVC4;
using namespace std;
namespace CVC4 {
+void SortInference::UnionFind::print(const char * c){
+ for( std::map< int, int >::iterator it = d_eqc.begin(); it != d_eqc.end(); ++it ){
+ Trace(c) << "s_" << it->first << " = s_" << it->second << ", ";
+ }
+ for( unsigned i=0; i<d_deq.size(); i++ ){
+ Trace(c) << "s_" << d_deq[i].first << " != s_" << d_deq[i].second << ", ";
+ }
+ Trace(c) << std::endl;
+}
+void SortInference::UnionFind::set( UnionFind& c ) {
+ clear();
+ for( std::map< int, int >::iterator it = c.d_eqc.begin(); it != c.d_eqc.end(); ++it ){
+ d_eqc[ it->first ] = it->second;
+ }
+ d_deq.insert( d_deq.end(), c.d_deq.begin(), c.d_deq.end() );
+}
+int SortInference::UnionFind::getRepresentative( int t ){
+ std::map< int, int >::iterator it = d_eqc.find( t );
+ if( it==d_eqc.end() || it->second==t ){
+ return t;
+ }else{
+ int rt = getRepresentative( it->second );
+ d_eqc[t] = rt;
+ return rt;
+ }
+}
+void SortInference::UnionFind::setEqual( int t1, int t2 ){
+ if( t1!=t2 ){
+ int rt1 = getRepresentative( t1 );
+ int rt2 = getRepresentative( t2 );
+ if( rt1>rt2 ){
+ d_eqc[rt1] = rt2;
+ }else{
+ d_eqc[rt2] = rt1;
+ }
+ }
+}
+bool SortInference::UnionFind::isValid() {
+ for( unsigned i=0; i<d_deq.size(); i++ ){
+ if( areEqual( d_deq[i].first, d_deq[i].second ) ){
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void SortInference::recordSubsort( int s ){
+ s = d_type_union_find.getRepresentative( s );
+ if( std::find( d_sub_sorts.begin(), d_sub_sorts.end(), s )==d_sub_sorts.end() ){
+ d_sub_sorts.push_back( s );
+ }
+}
void SortInference::printSort( const char* c, int t ){
- int rt = getRepresentative( t );
+ int rt = d_type_union_find.getRepresentative( t );
if( d_type_types.find( rt )!=d_type_types.end() ){
Trace(c) << d_type_types[rt];
}else{
@@ -43,30 +98,49 @@ void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){
std::map< Node, Node > var_bound;
process( assertions[i], var_bound );
}
- //print debug
- if( Trace.isOn("sort-inference") ){
- for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
- Trace("sort-inference") << it->first << " : ";
- if( !d_op_arg_types[ it->first ].empty() ){
- Trace("sort-inference") << "( ";
- for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){
- printSort( "sort-inference", d_op_arg_types[ it->first ][i] );
- Trace("sort-inference") << " ";
- }
- Trace("sort-inference") << ") -> ";
+ for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
+ Trace("sort-inference") << it->first << " : ";
+ if( !d_op_arg_types[ it->first ].empty() ){
+ Trace("sort-inference") << "( ";
+ for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){
+ recordSubsort( d_op_arg_types[ it->first ][i] );
+ printSort( "sort-inference", d_op_arg_types[ it->first ][i] );
+ Trace("sort-inference") << " ";
}
- printSort( "sort-inference", it->second );
- Trace("sort-inference") << std::endl;
+ Trace("sort-inference") << ") -> ";
}
- for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){
- Trace("sort-inference") << "Quantified formula " << it->first << " : " << std::endl;
- for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
- printSort( "sort-inference", it2->second );
- Trace("sort-inference") << std::endl;
- }
+ recordSubsort( it->second );
+ printSort( "sort-inference", it->second );
+ Trace("sort-inference") << std::endl;
+ }
+ for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){
+ Trace("sort-inference") << "Quantified formula : " << it->first << " : " << std::endl;
+ for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ printSort( "sort-inference", it2->second );
Trace("sort-inference") << std::endl;
}
+ Trace("sort-inference") << std::endl;
}
+
+ //determine monotonicity of sorts
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ Trace("sort-inference-debug") << "Process monotonicity for " << assertions[i] << std::endl;
+ std::map< Node, Node > var_bound;
+ processMonotonic( assertions[i], true, true, var_bound );
+ }
+
+ Trace("sort-inference") << "We have " << d_sub_sorts.size() << " sub-sorts : " << std::endl;
+ for( unsigned i=0; i<d_sub_sorts.size(); i++ ){
+ printSort( "sort-inference", d_sub_sorts[i] );
+ if( d_type_types.find( d_sub_sorts[i] )!=d_type_types.end() ){
+ Trace("sort-inference") << " is interpreted." << std::endl;
+ }else if( d_non_monotonic_sorts.find( d_sub_sorts[i] )==d_non_monotonic_sorts.end() ){
+ Trace("sort-inference") << " is monotonic." << std::endl;
+ }else{
+ Trace("sort-inference") << " is not monotonic." << std::endl;
+ }
+ }
+
if( doRewrite ){
//simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers)
for( unsigned i=0; i<assertions.size(); i++ ){
@@ -82,47 +156,43 @@ void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){
}
//add lemma enforcing introduced constants to be distinct?
}
- }
-}
-
-int SortInference::getRepresentative( int t ){
- std::map< int, int >::iterator it = d_type_union_find.find( t );
- if( it!=d_type_union_find.end() ){
- if( it->second==t ){
- return t;
- }else{
- int rt = getRepresentative( it->second );
- d_type_union_find[t] = rt;
- return rt;
+ }else if( !options::ufssSymBreak() ){
+ std::map< int, Node > constants;
+ //just add a bunch of unit lemmas
+ for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
+ int rt = d_type_union_find.getRepresentative( it->second );
+ if( d_op_arg_types[ it->first ].empty() && constants.find( rt )==constants.end() ){
+ constants[ rt ] = it->first;
+ }
}
- }else{
- return t;
+ //add unit lemmas for each constant
+ Node first_const;
+ for( std::map< int, Node >::iterator it = constants.begin(); it != constants.end(); ++it ){
+ if( first_const.isNull() ){
+ first_const = it->second;
+ }else{
+ Node eq = first_const.eqNode( it->second );
+ //eq = Rewriter::rewrite( eq );
+ Trace("sort-inference-lemma") << "Sort inference lemma : " << eq << std::endl;
+ assertions.push_back( eq );
+ }
+ }
+
+
}
+ initialSortCount = sortCount;
}
void SortInference::setEqual( int t1, int t2 ){
if( t1!=t2 ){
- int rt1 = getRepresentative( t1 );
- int rt2 = getRepresentative( t2 );
+ int rt1 = d_type_union_find.getRepresentative( t1 );
+ int rt2 = d_type_union_find.getRepresentative( t2 );
if( rt1!=rt2 ){
Trace("sort-inference-debug") << "Set equal : ";
printSort( "sort-inference-debug", rt1 );
Trace("sort-inference-debug") << " ";
printSort( "sort-inference-debug", rt2 );
Trace("sort-inference-debug") << std::endl;
- //check if they must be a type
- std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 );
- std::map< int, TypeNode >::iterator it2 = d_type_types.find( rt2 );
- if( it2!=d_type_types.end() ){
- if( it1==d_type_types.end() ){
- //swap sides
- int swap = rt1;
- rt1 = rt2;
- rt2 = swap;
- }else{
- Assert( rt1==rt2 );
- }
- }
/*
d_type_eq_class[rt1].insert( d_type_eq_class[rt1].end(), d_type_eq_class[rt2].begin(), d_type_eq_class[rt2].end() );
d_type_eq_class[rt2].clear();
@@ -132,7 +202,19 @@ void SortInference::setEqual( int t1, int t2 ){
}
Trace("sort-inference-debug") << "}" << std::endl;
*/
- d_type_union_find[rt2] = rt1;
+ if( rt2>rt1 ){
+ //swap
+ int swap = rt1;
+ rt1 = rt2;
+ rt2 = swap;
+ }
+ d_type_union_find.d_eqc[rt1] = rt2;
+ std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 );
+ if( it1!=d_type_types.end() ){
+ Assert( d_type_types.find( rt2 )==d_type_types.end() );
+ d_type_types[rt2] = it1->second;
+ d_type_types.erase( rt1 );
+ }
}
}
}
@@ -155,14 +237,17 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
Trace("sort-inference-debug") << "Process " << n << std::endl;
//add to variable bindings
if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- for( size_t i=0; i<n[0].getNumChildren(); i++ ){
- //TODO: try applying sort inference to quantified variables
- d_var_types[n][ n[0][i] ] = sortCount;
- sortCount++;
+ if( d_var_types.find( n )!=d_var_types.end() ){
+ return getIdForType( n.getType() );
+ }else{
+ for( size_t i=0; i<n[0].getNumChildren(); i++ ){
+ //apply sort inference to quantified variables
+ d_var_types[n][ n[0][i] ] = sortCount;
+ sortCount++;
- //type of the quantified variable must be the same
- //d_var_types[n][ n[0][i] ] = getIdForType( n[0][i].getType() );
- var_bound[ n[0][i] ] = n;
+ //type of the quantified variable must be the same
+ var_bound[ n[0][i] ] = n;
+ }
}
}
@@ -192,6 +277,9 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
if( n.getKind()==kind::EQUAL ){
//we only require that the left and right hand side must be equal
setEqual( child_types[0], child_types[1] );
+ //int eqType = getIdForType( n[0].getType() );
+ //setEqual( child_types[0], eqType );
+ //setEqual( child_types[1], eqType );
retType = getIdForType( n.getType() );
}else if( n.getKind()==kind::APPLY_UF ){
Node op = n.getOperator();
@@ -227,11 +315,11 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
//d_type_eq_class[sortCount].push_back( n );
}
retType = d_op_return_types[n];
- }else if( n.isConst() ){
- Trace("sort-inference-debug") << n << " is a constant." << std::endl;
+ //}else if( n.isConst() ){
+ // Trace("sort-inference-debug") << n << " is a constant." << std::endl;
//can be any type we want
- retType = sortCount;
- sortCount++;
+ // retType = sortCount;
+ // sortCount++;
}else{
Trace("sort-inference-debug") << n << " is a interpreted symbol." << std::endl;
//it is an interpretted term
@@ -251,9 +339,43 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
return retType;
}
+void SortInference::processMonotonic( Node n, bool pol, bool hasPol, std::map< Node, Node >& var_bound ) {
+ if( n.getKind()==kind::FORALL ){
+ for( unsigned i=0; i<n[0].getNumChildren(); i++ ){
+ var_bound[n[0][i]] = n;
+ }
+ processMonotonic( n[1], pol, hasPol, var_bound );
+ for( unsigned i=0; i<n[0].getNumChildren(); i++ ){
+ var_bound.erase( n[0][i] );
+ }
+ }else if( n.getKind()==kind::EQUAL ){
+ if( !hasPol || pol ){
+ for( unsigned i=0; i<2; i++ ){
+ if( var_bound.find( n[i] )==var_bound.end() ){
+ int sid = getSortId( var_bound[n[i]], n[i] );
+ d_non_monotonic_sorts[sid] = true;
+ break;
+ }
+ }
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool npol = pol;
+ bool nhasPol = hasPol;
+ if( n.getKind()==kind::NOT || ( n.getKind()==kind::IMPLIES && i==0 ) ){
+ npol = !npol;
+ }
+ if( ( n.getKind()==kind::ITE && i==0 ) || n.getKind()==kind::XOR || n.getKind()==kind::IFF ){
+ nhasPol = false;
+ }
+ processMonotonic( n[i], npol, nhasPol, var_bound );
+ }
+ }
+}
+
TypeNode SortInference::getOrCreateTypeForId( int t, TypeNode pref ){
- int rt = getRepresentative( t );
+ int rt = d_type_union_find.getRepresentative( t );
if( d_type_types.find( rt )!=d_type_types.end() ){
return d_type_types[rt];
}else{
@@ -278,7 +400,7 @@ TypeNode SortInference::getOrCreateTypeForId( int t, TypeNode pref ){
}
TypeNode SortInference::getTypeForId( int t ){
- int rt = getRepresentative( t );
+ int rt = d_type_union_find.getRepresentative( t );
if( d_type_types.find( rt )!=d_type_types.end() ){
return d_type_types[rt];
}else{
@@ -414,15 +536,71 @@ Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){
}
int SortInference::getSortId( Node n ) {
Node op = n.getKind()==kind::APPLY_UF ? n.getOperator() : n;
- return getRepresentative( d_op_return_types[op] );
+ if( d_op_return_types.find( op )!=d_op_return_types.end() ){
+ return d_type_union_find.getRepresentative( d_op_return_types[op] );
+ }else{
+ return 0;
+ }
}
int SortInference::getSortId( Node f, Node v ) {
- return getRepresentative( d_var_types[f][v] );
+ if( d_var_types.find( f )!=d_var_types.end() ){
+ return d_type_union_find.getRepresentative( d_var_types[f][v] );
+ }else{
+ return 0;
+ }
}
void SortInference::setSkolemVar( Node f, Node v, Node sk ){
+ Trace("sort-inference-temp") << "Set skolem var for " << f << ", variable " << v << std::endl;
+ if( isWellSortedFormula( f ) && d_var_types.find( f )==d_var_types.end() ){
+ std::map< Node, Node > var_bound;
+ process( f, var_bound );
+ }
d_op_return_types[sk] = getSortId( f, v );
+ Trace("sort-inference-temp") << "Set skolem sort id for " << sk << " to " << d_op_return_types[sk] << std::endl;
+}
+
+bool SortInference::isWellSortedFormula( Node n ) {
+ if( n.getType().isBoolean() && n.getKind()!=kind::APPLY_UF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isWellSortedFormula( n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return isWellSorted( n );
+ }
+}
+
+bool SortInference::isWellSorted( Node n ) {
+ if( getSortId( n )==0 ){
+ return false;
+ }else{
+ if( n.getKind()==kind::APPLY_UF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int s1 = getSortId( n[i] );
+ int s2 = d_type_union_find.getRepresentative( d_op_arg_types[ n.getOperator() ][i] );
+ if( s1!=s2 ){
+ return false;
+ }
+ if( !isWellSorted( n[i] ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
+
+void SortInference::getSortConstraints( Node n, UnionFind& uf ) {
+ if( n.getKind()==kind::APPLY_UF ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getSortConstraints( n[i], uf );
+ uf.setEqual( getSortId( n[i] ), d_type_union_find.getRepresentative( d_op_arg_types[ n.getOperator() ][i] ) );
+ }
+ }
}
}/* CVC4 namespace */
diff --git a/src/util/sort_inference.h b/src/util/sort_inference.h
index 1bcb8a208..8f0fc5e9f 100644
--- a/src/util/sort_inference.h
+++ b/src/util/sort_inference.h
@@ -28,11 +28,33 @@ namespace CVC4 {
class SortInference{
private:
- //for debugging
- //std::map< int, std::vector< Node > > d_type_eq_class;
+ //all subsorts
+ std::vector< int > d_sub_sorts;
+ std::map< int, bool > d_non_monotonic_sorts;
+ void recordSubsort( int s );
+public:
+ class UnionFind {
+ public:
+ UnionFind(){}
+ UnionFind( UnionFind& c ){
+ set( c );
+ }
+ std::map< int, int > d_eqc;
+ //pairs that must be disequal
+ std::vector< std::pair< int, int > > d_deq;
+ void print(const char * c);
+ void clear() { d_eqc.clear(); d_deq.clear(); }
+ void set( UnionFind& c );
+ int getRepresentative( int t );
+ void setEqual( int t1, int t2 );
+ void setDisequal( int t1, int t2 ){ d_deq.push_back( std::pair< int, int >( t1, t2 ) ); }
+ bool areEqual( int t1, int t2 ) { return getRepresentative( t1 )==getRepresentative( t2 ); }
+ bool isValid();
+ };
private:
int sortCount;
- std::map< int, int > d_type_union_find;
+ int initialSortCount;
+ UnionFind d_type_union_find;
std::map< int, TypeNode > d_type_types;
std::map< TypeNode, int > d_id_for_types;
//for apply uf operators
@@ -41,12 +63,17 @@ private:
//for bound variables
std::map< Node, std::map< Node, int > > d_var_types;
//get representative
- int getRepresentative( int t );
void setEqual( int t1, int t2 );
int getIdForType( TypeNode tn );
void printSort( const char* c, int t );
//process
int process( Node n, std::map< Node, Node >& var_bound );
+
+//for monotonicity inference
+private:
+ void processMonotonic( Node n, bool pol, bool hasPol, std::map< Node, Node >& var_bound );
+
+//for rewriting
private:
//mapping from old symbols to new symbols
std::map< Node, Node > d_symbol_map;
@@ -60,15 +87,24 @@ private:
Node getNewSymbol( Node old, TypeNode tn );
//simplify
Node simplify( Node n, std::map< Node, Node >& var_bound );
+
public:
- SortInference() : sortCount( 0 ){}
+ SortInference() : sortCount( 1 ){}
~SortInference(){}
void simplify( std::vector< Node >& assertions, bool doRewrite = false );
+ //get sort id for term n
int getSortId( Node n );
+ //get sort id for variable of quantified formula f
int getSortId( Node f, Node v );
//set that sk is the skolem variable of v for quantifier f
void setSkolemVar( Node f, Node v, Node sk );
+public:
+ //is well sorted
+ bool isWellSortedFormula( Node n );
+ bool isWellSorted( Node n );
+ //get constraints for being well-typed according to computed sub-types
+ void getSortConstraints( Node n, SortInference::UnionFind& uf );
};
}
diff --git a/src/util/statistics_registry.h b/src/util/statistics_registry.h
index 3bec559d5..8ffc60d17 100644
--- a/src/util/statistics_registry.h
+++ b/src/util/statistics_registry.h
@@ -847,7 +847,7 @@ public:
* like in this example, which takes the place of the declaration of a
* statistics field "d_checkTimer":
*
- * KEEP_STATISTIC(TimerStat, d_checkTimer, "theory::uf::morgan::checkTime");
+ * KEEP_STATISTIC(TimerStat, d_checkTimer, "theory::uf::checkTime");
*
* If any args need to be passed to the constructor, you can specify
* them after the string.
diff --git a/src/util/util_model.cpp b/src/util/util_model.cpp
index ab4c95ea5..1c2dc2edf 100644
--- a/src/util/util_model.cpp
+++ b/src/util/util_model.cpp
@@ -24,7 +24,7 @@ using namespace std;
namespace CVC4 {
-std::ostream& operator<<(std::ostream& out, Model& m) {
+std::ostream& operator<<(std::ostream& out, const Model& m) {
smt::SmtScope smts(&m.d_smt);
Expr::dag::Scope scope(out, false);
Printer::getPrinter(options::outputLanguage())->toStream(out, m);
diff --git a/src/util/util_model.h b/src/util/util_model.h
index 535493a2d..e5bd1f955 100644
--- a/src/util/util_model.h
+++ b/src/util/util_model.h
@@ -29,10 +29,14 @@ class Command;
class SmtEngine;
class Model;
-std::ostream& operator<<(std::ostream&, Model&);
+std::ostream& operator<<(std::ostream&, const Model&);
class Model {
- friend std::ostream& operator<<(std::ostream&, Model&);
+ friend std::ostream& operator<<(std::ostream&, const Model&);
+ friend class SmtEngine;
+
+ /** the input name (file name, etc.) this model is associated to */
+ std::string d_inputName;
protected:
/** The SmtEngine we're associated with */
@@ -50,6 +54,10 @@ public:
const Command* getCommand(size_t i) const;
/** get the smt engine that this model is hooked up to */
SmtEngine* getSmtEngine() { return &d_smt; }
+ /** get the smt engine (as a pointer-to-const) that this model is hooked up to */
+ const SmtEngine* getSmtEngine() const { return &d_smt; }
+ /** get the input name (file name, etc.) this model is associated to */
+ std::string getInputName() const { return d_inputName; }
public:
/** get value for expression */
diff --git a/test/Makefile.am b/test/Makefile.am
index 6cccca05c..104d40ab1 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -51,8 +51,11 @@ subdirs_to_check = \
regress/regress0/push-pop/boolean \
regress/regress0/precedence \
regress/regress0/preprocess \
+ regress/regress0/tptp \
regress/regress0/unconstrained \
regress/regress0/decision \
+ regress/regress0/fmf \
+ regress/regress0/strings \
regress/regress1 \
regress/regress2 \
regress/regress3
diff --git a/test/regress/regress0/Makefile.am b/test/regress/regress0/Makefile.am
index 12d7ab397..8ae9b3ae2 100644
--- a/test/regress/regress0/Makefile.am
+++ b/test/regress/regress0/Makefile.am
@@ -1,7 +1,11 @@
-SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess unconstrained decision
-DIST_SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess unconstrained decision
+SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess tptp unconstrained decision fmf strings
+DIST_SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess tptp unconstrained decision fmf strings
+
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
-BINARY = cvc4
LOG_COMPILER = @srcdir@/../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -42,6 +46,7 @@ SMT_TESTS = \
# Regression tests for SMT2 inputs
SMT2_TESTS = \
+ chained-equality.smt2 \
ite2.smt2 \
ite3.smt2 \
ite4.smt2 \
@@ -100,17 +105,7 @@ CVC_TESTS = \
print_lambda.cvc
# Regression tests for TPTP inputs
-TPTP_TESTS = \
- tptp_parser.p \
- tptp_parser2.p \
- tptp_parser3.p \
- tptp_parser4.p \
- tptp_parser5.p \
- tptp_parser6.p \
- tptp_parser7.p \
- tptp_parser8.p \
- tptp_parser9.p \
- tptp_parser10.p
+TPTP_TESTS =
# Regression tests derived from bug reports
BUG_TESTS = \
@@ -148,8 +143,15 @@ BUG_TESTS = \
bug480.smt2 \
bug484.smt2 \
bug486.cvc \
- bug497.cvc \
- bug507.smt2
+ bug507.smt2 \
+ bug512.smt2 \
+ bug512.minimized.smt2 \
+ bug516.smt2 \
+ bug519.smt2 \
+ bug520.smt2 \
+ bug521.smt2 \
+ bug521.minimized.smt2 \
+ bug522.smt2
TESTS = $(SMT_TESTS) $(SMT2_TESTS) $(CVC_TESTS) $(TPTP_TESTS) $(BUG_TESTS)
diff --git a/test/regress/regress0/arith/Makefile.am b/test/regress/regress0/arith/Makefile.am
index 40f04b239..6897ee3c4 100644
--- a/test/regress/regress0/arith/Makefile.am
+++ b/test/regress/regress0/arith/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = . integers
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -23,7 +27,6 @@ TESTS = \
delta-minimized-row-vector-bug.smt \
fuzz_3-eq.smt \
leq.01.smt \
- DTP_k2_n35_c175_s15.smt2 \
mod.01.smt2 \
mod.02.smt2 \
mod.03.smt2 \
@@ -35,7 +38,6 @@ TESTS = \
div.06.smt2 \
div.07.smt2 \
div.08.smt2 \
- div.09.smt2 \
mult.01.smt2 \
mult.02.smt2 \
bug443.delta01.smt \
@@ -52,7 +54,8 @@ EXTRA_DIST = $(TESTS) \
miplib-pp08a-3000.smt \
miplib-pp08a-3000.smt2 \
miplib-opt1217--27.smt.expect \
- miplib-pp08a-3000.smt.expect
+ miplib-pp08a-3000.smt.expect \
+ div.09.smt2
#if CVC4_BUILD_PROFILE_COMPETITION
#else
diff --git a/test/regress/regress0/arith/div.09.smt2 b/test/regress/regress0/arith/div.09.smt2
index 2f1bca63a..9bcb93476 100644
--- a/test/regress/regress0/arith/div.09.smt2
+++ b/test/regress/regress0/arith/div.09.smt2
@@ -1,4 +1,7 @@
-; EXPECT: (error "Non-linear term was asserted to arithmetic in a linear logic.")
+; EXPECT: (error "A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic: (/ n n)
+; EXPECT: if you only use division (or modulus) by a constant value, or if you only use the divisibility-by-k predicate, try using the --rewrite-divk option.
+; EXPECT: The fact in question: (>= (+ (* (- 1) (/ n n)) termITE_132) 0)
+; EXPECT: ")
; EXIT: 1
(set-logic QF_LRA)
(set-info :status unknown)
diff --git a/test/regress/regress0/arith/integers/Makefile.am b/test/regress/regress0/arith/integers/Makefile.am
index efd5aa909..3511c6b30 100644
--- a/test/regress/regress0/arith/integers/Makefile.am
+++ b/test/regress/regress0/arith/integers/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -20,9 +24,9 @@ MAKEFLAGS = -k
TESTS = \
arith-int-004.cvc \
- arith-int-007.cvc \
arith-int-011.cvc \
arith-int-012.cvc \
+ arith-int-013.cvc \
arith-int-022.cvc \
arith-int-024.cvc \
arith-int-042.cvc \
@@ -31,10 +35,10 @@ TESTS = \
arith-int-048.cvc \
arith-int-050.cvc \
arith-int-084.cvc \
- arith-int-097.cvc \
- arith-int-085.cvc
+ arith-int-085.cvc \
+ arith-int-097.cvc
-EXTRA_DIST = $(TESTS)
+EXTRA_DIST = $(TESTS) \
arith-int-001.cvc \
arith-int-002.cvc \
arith-int-003.cvc \
@@ -105,7 +109,6 @@ EXTRA_DIST = $(TESTS)
arith-int-079.cvc \
arith-int-080.cvc \
arith-int-081.cvc \
- arith-int-082.cvc \
arith-int-083.cvc \
arith-int-086.cvc \
arith-int-087.cvc \
@@ -123,8 +126,9 @@ EXTRA_DIST = $(TESTS)
arith-int-100.cvc
FAILING_TESTS = \
- arith-int-024.cvc \
- arith-int-013.cvc
+ arith-int-007.cvc \
+ arith-int-082.cvc \
+ arith-int-098.cvc
#if CVC4_BUILD_PROFILE_COMPETITION
#else
diff --git a/test/regress/regress0/arith/mult.02.smt2 b/test/regress/regress0/arith/mult.02.smt2
index d690e38e8..54b876d38 100644
--- a/test/regress/regress0/arith/mult.02.smt2
+++ b/test/regress/regress0/arith/mult.02.smt2
@@ -1,4 +1,6 @@
-; EXPECT: (error "Non-linear term was asserted to arithmetic in a linear logic.")
+; EXPECT: (error "A non-linear fact was asserted to arithmetic in a linear logic.
+; EXPECT: The fact in question: (>= (* (- 1) (* n n)) (- 1))
+; EXPECT: ")
; EXIT: 1
(set-logic QF_LRA)
(set-info :status unknown)
diff --git a/test/regress/regress0/arrays/Makefile.am b/test/regress/regress0/arrays/Makefile.am
index e8642bc4f..33f05ab40 100644
--- a/test/regress/regress0/arrays/Makefile.am
+++ b/test/regress/regress0/arrays/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/aufbv/Makefile.am b/test/regress/regress0/aufbv/Makefile.am
index 937123bf7..e151a4846 100644
--- a/test/regress/regress0/aufbv/Makefile.am
+++ b/test/regress/regress0/aufbv/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -20,6 +24,7 @@ TESTS = \
bug347.smt \
bug348.smt \
bug451.smt \
+ bug509.smt \
try5_small_difret_functions_wp_su.set_char_quoting.il.wp.delta01.smt \
try3_sameret_functions_fse-bfs_tac.calc_next.il.fse-bfs.delta01.smt \
diseqprop.01.smt \
diff --git a/test/regress/regress0/aufbv/bug509.smt b/test/regress/regress0/aufbv/bug509.smt
new file mode 100644
index 000000000..b23f9c6d5
--- /dev/null
+++ b/test/regress/regress0/aufbv/bug509.smt
@@ -0,0 +1,117 @@
+(benchmark fuzzsmt
+:logic QF_AUFBV
+:status sat
+:extrafuns ((v0 BitVec[1]))
+:extrafuns ((v1 BitVec[13]))
+:extrafuns ((v2 BitVec[5]))
+:extrafuns ((a3 Array[1:16]))
+:formula
+(let (?e4 bv1[1])
+(let (?e5 (sign_extend[1] v1))
+(let (?e6 (bvneg v0))
+(let (?e7 (rotate_right[0] ?e4))
+(let (?e8 (bvnand v1 v1))
+(let (?e9 (zero_extend[11] v2))
+(let (?e10 (store a3 (extract[14:14] ?e9) (sign_extend[3] ?e8)))
+(let (?e11 (select a3 ?e6))
+(let (?e12 (select a3 (extract[14:14] ?e11)))
+(let (?e13 (select a3 (extract[14:14] ?e11)))
+(let (?e14 (select a3 ?e4))
+(let (?e15 (select a3 ?e4))
+(let (?e16 (ite (bvsgt ?e14 (zero_extend[15] ?e6)) bv1[1] bv0[1]))
+(let (?e17 (bvnand (sign_extend[12] ?e4) ?e8))
+(let (?e18 (ite (bvsge ?e12 ?e14) bv1[1] bv0[1]))
+(let (?e19 (bvxor ?e15 (zero_extend[15] ?e7)))
+(let (?e20 (ite (bvslt (sign_extend[12] ?e6) v1) bv1[1] bv0[1]))
+(let (?e21 (bvand ?e11 (sign_extend[15] ?e16)))
+(let (?e22 (ite (bvult (sign_extend[8] v2) v1) bv1[1] bv0[1]))
+(let (?e23 (bvsrem (sign_extend[2] ?e5) ?e11))
+(let (?e24 (bvurem ?e9 ?e12))
+(let (?e25 (bvashr (zero_extend[3] ?e8) ?e19))
+(let (?e26 (bvlshr ?e13 (sign_extend[15] ?e20)))
+(let (?e27 (ite (= ?e13 ?e12) bv1[1] bv0[1]))
+(let (?e28 (bvxnor v0 v0))
+(flet ($e29 (bvugt (sign_extend[15] ?e4) ?e26))
+(flet ($e30 (bvugt ?e11 (sign_extend[15] v0)))
+(flet ($e31 (distinct (zero_extend[11] v2) ?e12))
+(flet ($e32 (bvsge ?e14 (zero_extend[15] ?e18)))
+(flet ($e33 (bvsle (sign_extend[15] ?e27) ?e19))
+(flet ($e34 (distinct (sign_extend[12] ?e16) v1))
+(flet ($e35 (bvsle ?e24 ?e15))
+(flet ($e36 (distinct ?e13 (zero_extend[15] ?e16)))
+(flet ($e37 (bvugt ?e22 ?e18))
+(flet ($e38 (bvslt ?e19 ?e24))
+(flet ($e39 (bvule ?e26 ?e9))
+(flet ($e40 (bvslt ?e7 ?e16))
+(flet ($e41 (bvuge ?e21 ?e9))
+(flet ($e42 (bvule ?e24 ?e9))
+(flet ($e43 (bvuge ?e7 ?e16))
+(flet ($e44 (distinct (zero_extend[12] ?e28) v1))
+(flet ($e45 (bvsge ?e4 v0))
+(flet ($e46 (bvule ?e17 (sign_extend[12] ?e22)))
+(flet ($e47 (bvugt ?e15 (zero_extend[15] ?e27)))
+(flet ($e48 (bvsgt ?e12 ?e24))
+(flet ($e49 (bvsgt ?e13 ?e13))
+(flet ($e50 (bvslt ?e20 ?e6))
+(flet ($e51 (bvsgt ?e19 (zero_extend[15] ?e28)))
+(flet ($e52 (bvsgt ?e21 (sign_extend[15] ?e7)))
+(flet ($e53 (bvslt ?e9 ?e15))
+(flet ($e54 (bvule ?e21 ?e12))
+(flet ($e55 (= ?e24 (zero_extend[3] v1)))
+(flet ($e56 (bvsle v0 ?e16))
+(flet ($e57 (= (sign_extend[15] ?e4) ?e12))
+(flet ($e58 (distinct (sign_extend[2] ?e5) ?e9))
+(flet ($e59 (bvult (sign_extend[15] ?e22) ?e25))
+(flet ($e60 (bvsge ?e20 ?e20))
+(flet ($e61 (distinct ?e14 ?e24))
+(flet ($e62 (bvuge (sign_extend[15] v0) ?e19))
+(flet ($e63 (bvuge ?e25 (sign_extend[3] ?e8)))
+(flet ($e64 (bvult ?e4 ?e7))
+(flet ($e65 (bvsle (zero_extend[12] ?e16) ?e17))
+(flet ($e66 (bvule ?e26 ?e9))
+(flet ($e67 (bvugt ?e14 ?e23))
+(flet ($e68 (or $e37 $e45))
+(flet ($e69 (or $e31 $e30))
+(flet ($e70 (iff $e46 $e65))
+(flet ($e71 (or $e42 $e44))
+(flet ($e72 (iff $e43 $e69))
+(flet ($e73 (iff $e32 $e35))
+(flet ($e74 (or $e49 $e49))
+(flet ($e75 (or $e33 $e51))
+(flet ($e76 (xor $e53 $e61))
+(flet ($e77 (implies $e38 $e34))
+(flet ($e78 (and $e57 $e41))
+(flet ($e79 (iff $e50 $e68))
+(flet ($e80 (implies $e73 $e77))
+(flet ($e81 (if_then_else $e60 $e62 $e55))
+(flet ($e82 (and $e56 $e54))
+(flet ($e83 (if_then_else $e67 $e80 $e81))
+(flet ($e84 (iff $e72 $e36))
+(flet ($e85 (if_then_else $e83 $e39 $e59))
+(flet ($e86 (iff $e58 $e29))
+(flet ($e87 (and $e47 $e64))
+(flet ($e88 (not $e40))
+(flet ($e89 (not $e82))
+(flet ($e90 (xor $e76 $e78))
+(flet ($e91 (not $e79))
+(flet ($e92 (if_then_else $e74 $e85 $e89))
+(flet ($e93 (xor $e75 $e92))
+(flet ($e94 (not $e86))
+(flet ($e95 (if_then_else $e84 $e88 $e70))
+(flet ($e96 (and $e91 $e94))
+(flet ($e97 (and $e96 $e95))
+(flet ($e98 (not $e97))
+(flet ($e99 (if_then_else $e90 $e98 $e52))
+(flet ($e100 (implies $e71 $e48))
+(flet ($e101 (or $e93 $e87))
+(flet ($e102 (xor $e100 $e66))
+(flet ($e103 (if_then_else $e102 $e102 $e63))
+(flet ($e104 (if_then_else $e101 $e99 $e101))
+(flet ($e105 (xor $e103 $e103))
+(flet ($e106 (or $e104 $e105))
+(flet ($e107 (and $e106 (not (= ?e12 bv0[16]))))
+(flet ($e108 (and $e107 (not (= ?e11 bv0[16]))))
+(flet ($e109 (and $e108 (not (= ?e11 (bvnot bv0[16])))))
+$e109
+)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+
diff --git a/test/regress/regress0/auflia/Makefile.am b/test/regress/regress0/auflia/Makefile.am
index 5a6ab9e2b..ca1fc25d3 100644
--- a/test/regress/regress0/auflia/Makefile.am
+++ b/test/regress/regress0/auflia/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -20,7 +24,6 @@ TESTS = \
fuzz03.smt \
fuzz04.smt \
fuzz05.smt \
- fuzz06.smt \
fuzz-error232.smt \
fuzz-error1099.smt \
a17.smt \
diff --git a/test/regress/regress0/bug512.minimized.smt2 b/test/regress/regress0/bug512.minimized.smt2
new file mode 100644
index 000000000..5fcbf5a9f
--- /dev/null
+++ b/test/regress/regress0/bug512.minimized.smt2
@@ -0,0 +1,8 @@
+; EXPECT: unknown
+; EXIT: 0
+(set-logic UF)
+(declare-sort T 0)
+(declare-fun bool_2_U (Bool) T)
+(declare-fun U_2_bool (T) Bool)
+(assert (forall ((x T)) (= (bool_2_U (U_2_bool x)) x)))
+(check-sat)
diff --git a/test/regress/regress0/bug512.smt2 b/test/regress/regress0/bug512.smt2
new file mode 100644
index 000000000..c9aadfe6e
--- /dev/null
+++ b/test/regress/regress0/bug512.smt2
@@ -0,0 +1,147 @@
+; COMMAND-LINE: --tlimit-per 2500 -iq
+; EXPECT: unknown
+; EXPECT: (:reason-unknown timeout)
+; EXPECT: unsat
+; EXIT: 20
+(set-option :print-success false)
+(set-info :smt-lib-version 2.0)
+;(set-option :AUTO_CONFIG false)
+;(set-option :MODEL_HIDE_UNUSED_PARTITIONS false)
+;(set-option :MODEL_V2 true)
+;(set-option :ASYNC_COMMANDS false)
+;(set-option :PHASE_SELECTION 0)
+;(set-option :RESTART_STRATEGY 0)
+;(set-option :RESTART_FACTOR |1.5|)
+;(set-option :ARITH_RANDOM_INITIAL_VALUE true)
+;(set-option :CASE_SPLIT 3)
+;(set-option :DELAY_UNITS true)
+;(set-option :DELAY_UNITS_THRESHOLD 16)
+;(set-option :NNF_SK_HACK true)
+;(set-option :MBQI false)
+;(set-option :QI_EAGER_THRESHOLD 100)
+;(set-option :QI_COST |"(+ weight generation)"|)
+;(set-option :TYPE_CHECK true)
+;(set-option :BV_REFLECT true)
+; done setting options
+
+; Boogie universal background predicate
+; Copyright (c) 2004-2010, Microsoft Corp.
+(set-info :category "industrial")
+(declare-sort |T@U| 0)
+(declare-sort |T@T| 0)
+(declare-fun real_pow (Real Real) Real)
+(declare-fun UOrdering2 (|T@U| |T@U|) Bool)
+(declare-fun UOrdering3 (|T@T| |T@U| |T@U|) Bool)
+
+(declare-fun tickleBool (Bool) Bool)
+(assert (and (tickleBool true) (tickleBool false)))
+(declare-fun Ctor (T@T) Int)
+(declare-fun intType () T@T)
+(declare-fun realType () T@T)
+(declare-fun boolType () T@T)
+(declare-fun int_2_U (Int) T@U)
+(declare-fun U_2_int (T@U) Int)
+(declare-fun type (T@U) T@T)
+(declare-fun real_2_U (Real) T@U)
+(declare-fun U_2_real (T@U) Real)
+(declare-fun bool_2_U (Bool) T@U)
+(declare-fun U_2_bool (T@U) Bool)
+(declare-fun %lbl%+67 () Bool)
+(declare-fun i@0 () Int)
+(declare-fun x@@5 () Int)
+(declare-fun y@@1 () Int)
+(declare-fun i@1 () Int)
+(declare-fun %lbl%@186 () Bool)
+(declare-fun %lbl%+69 () Bool)
+(declare-fun %lbl%@157 () Bool)
+(declare-fun %lbl%+65 () Bool)
+(declare-fun %lbl%+63 () Bool)
+(declare-fun %lbl%@125 () Bool)
+(declare-fun %lbl%+97 () Bool)
+(assert (and
+(= (Ctor intType) 0)
+(= (Ctor realType) 1)
+(= (Ctor boolType) 2)
+(forall ((arg0 Int) ) (! (= (U_2_int (int_2_U arg0)) arg0)
+ :qid |typeInv:U_2_int|
+ :pattern ( (int_2_U arg0))
+))
+(forall ((x T@U) ) (! (=> (= (type x) intType) (= (int_2_U (U_2_int x)) x))
+ :qid |cast:U_2_int|
+ :pattern ( (U_2_int x))
+))
+(forall ((arg0@@0 Int) ) (! (= (type (int_2_U arg0@@0)) intType)
+ :qid |funType:int_2_U|
+ :pattern ( (int_2_U arg0@@0))
+))
+(forall ((arg0@@1 Real) ) (! (= (U_2_real (real_2_U arg0@@1)) arg0@@1)
+ :qid |typeInv:U_2_real|
+ :pattern ( (real_2_U arg0@@1))
+))
+(forall ((x@@0 T@U) ) (! (=> (= (type x@@0) realType) (= (real_2_U (U_2_real x@@0)) x@@0))
+ :qid |cast:U_2_real|
+ :pattern ( (U_2_real x@@0))
+))
+(forall ((arg0@@2 Real) ) (! (= (type (real_2_U arg0@@2)) realType)
+ :qid |funType:real_2_U|
+ :pattern ( (real_2_U arg0@@2))
+))
+(forall ((arg0@@3 Bool) ) (! (= (U_2_bool (bool_2_U arg0@@3)) arg0@@3)
+ :qid |typeInv:U_2_bool|
+ :pattern ( (bool_2_U arg0@@3))
+))
+(forall ((x@@1 T@U) ) (! (=> (= (type x@@1) boolType) (= (bool_2_U (U_2_bool x@@1)) x@@1))
+ :qid |cast:U_2_bool|
+ :pattern ( (U_2_bool x@@1))
+))
+(forall ((arg0@@4 Bool) ) (! (= (type (bool_2_U arg0@@4)) boolType)
+ :qid |funType:bool_2_U|
+ :pattern ( (bool_2_U arg0@@4))
+))))
+(assert (forall ((x@@2 T@U) ) (! (UOrdering2 x@@2 x@@2)
+ :qid |bg:subtype-refl|
+ :no-pattern (U_2_int x@@2)
+ :no-pattern (U_2_bool x@@2)
+)))
+(assert (forall ((x@@3 T@U) (y T@U) (z T@U) ) (! (let ((alpha (type x@@3)))
+(=> (and
+(= (type y) alpha)
+(= (type z) alpha)
+(UOrdering2 x@@3 y)
+(UOrdering2 y z)) (UOrdering2 x@@3 z)))
+ :qid |bg:subtype-trans|
+ :pattern ( (UOrdering2 x@@3 y) (UOrdering2 y z))
+)))
+(assert (forall ((x@@4 T@U) (y@@0 T@U) ) (! (let ((alpha@@0 (type x@@4)))
+(=> (= (type y@@0) alpha@@0) (=> (and
+(UOrdering2 x@@4 y@@0)
+(UOrdering2 y@@0 x@@4)) (= x@@4 y@@0))))
+ :qid |bg:subtype-antisymm|
+ :pattern ( (UOrdering2 x@@4 y@@0) (UOrdering2 y@@0 x@@4))
+)))
+(push 1)
+(set-info :boogie-vc-id foo)
+(assert (not
+(let ((anon3_LoopBody_correct (=> (! (and %lbl%+67 true) :lblpos +67) (=> (and
+(< i@0 (+ x@@5 y@@1))
+(= i@1 (+ i@0 1))) (and
+(! (or %lbl%@186 (<= i@1 (+ x@@5 y@@1))) :lblneg @186)
+(=> (<= i@1 (+ x@@5 y@@1)) true))))))
+(let ((anon3_LoopDone_correct (=> (! (and %lbl%+69 true) :lblpos +69) (=> (<= (+ x@@5 y@@1) i@0) (and
+(! (or %lbl%@157 (= i@0 (- x@@5 y@@1))) :lblneg @157)
+(=> (= i@0 (- x@@5 y@@1)) true))))))
+(let ((anon3_LoopHead_correct (=> (! (and %lbl%+65 true) :lblpos +65) (=> (<= i@0 (+ x@@5 y@@1)) (and
+anon3_LoopDone_correct
+anon3_LoopBody_correct)))))
+(let ((anon0_correct (=> (! (and %lbl%+63 true) :lblpos +63) (and
+(! (or %lbl%@125 (<= x@@5 (+ x@@5 y@@1))) :lblneg @125)
+(=> (<= x@@5 (+ x@@5 y@@1)) anon3_LoopHead_correct)))))
+(let ((PreconditionGeneratedEntry_correct (=> (! (and %lbl%+97 true) :lblpos +97) (=> (>= y@@1 0) anon0_correct))))
+PreconditionGeneratedEntry_correct)))))
+))
+(check-sat)
+(get-info :reason-unknown)
+;(labels)
+(assert %lbl%@157)
+(check-sat)
+(pop 1)
diff --git a/test/regress/regress0/bug516.smt2 b/test/regress/regress0/bug516.smt2
new file mode 100644
index 000000000..b5f5d49eb
--- /dev/null
+++ b/test/regress/regress0/bug516.smt2
@@ -0,0 +1,16 @@
+; COMMAND-LINE: --finite-model-find --fmf-bound-int
+; EXPECT: sat
+; EXIT: 10
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :incremental true)
+(declare-fun P (Int) Bool)
+(declare-fun ten () Int)
+
+(assert (forall ((x Int)) (=> (<= 1 x ten) (P x))))
+
+(push)
+(assert (= ten 10))
+
+(check-sat)
+(pop)
diff --git a/test/regress/regress0/bug519.smt2 b/test/regress/regress0/bug519.smt2
new file mode 100644
index 000000000..b3a2950a6
--- /dev/null
+++ b/test/regress/regress0/bug519.smt2
@@ -0,0 +1,76 @@
+; COMMAND-LINE: -mi
+; EXPECT: unknown
+; EXPECT: unsat
+; EXIT: 20
+
+(set-logic ALL_SUPPORTED)
+
+; must make parts 1 through 6 with different deadlines
+
+; part 1 must be available for part 2
+; parts 3 and 4 must be available for part 5
+; all parts must be available for part 6
+
+; start/complete is the timestep when a part is started/finished
+(declare-fun start (Int) Int)
+(declare-fun complete (Int) Int)
+
+(define-fun before ((i Int) (j Int)) Bool (< (complete i) (start j)))
+
+(assert (before 1 2))
+(assert (before 3 5))
+(assert (before 4 5))
+(assert (before 1 6))
+(assert (before 2 6))
+(assert (before 3 6))
+(assert (before 4 6))
+(assert (before 5 6))
+
+; part 1 takes 2 units of time
+; part 2 takes 3
+; part 3 takes 3
+; part 4 takes 1
+; part 5 takes 2
+; part 6 takes 1
+
+(define-fun requires ((i Int) (j Int)) Bool (= (complete i) (+ (start i) j)))
+
+(assert (requires 1 2))
+(assert (requires 2 3))
+(assert (requires 3 3))
+(assert (requires 4 1))
+(assert (requires 5 2))
+(assert (requires 6 1))
+
+(assert (>= (start 1) 0))
+(assert (>= (start 2) 0))
+(assert (>= (start 3) 0))
+(assert (>= (start 4) 0))
+(assert (>= (start 5) 0))
+(assert (>= (start 6) 0))
+
+(define-fun cost () Int (complete 6))
+
+(define-fun parallel ((t Int)) Int
+ (+ (ite (<= (start 1) t (complete 1)) 1 0)
+ (ite (<= (start 2) t (complete 2)) 1 0)
+ (ite (<= (start 3) t (complete 3)) 1 0)
+ (ite (<= (start 4) t (complete 4)) 1 0)
+ (ite (<= (start 5) t (complete 5)) 1 0)
+ (ite (<= (start 6) t (complete 6)) 1 0)))
+
+(declare-fun cost2 () Int)
+(assert (= cost2 cost))
+
+(declare-fun max-parallel () Int)
+(assert (forall ((t Int)) (=> (<= 0 t cost2) (>= max-parallel (parallel t)))))
+
+(check-sat)
+;(get-model)
+;(get-value (cost2))
+;(get-value ((parallel 1)))
+;(get-value ((=> (<= 0 1 cost2) (>= max-parallel (parallel 1)))))
+
+(assert (< cost 8))
+
+(check-sat)
diff --git a/test/regress/regress0/bug520.smt2 b/test/regress/regress0/bug520.smt2
new file mode 100644
index 000000000..4bdb968d8
--- /dev/null
+++ b/test/regress/regress0/bug520.smt2
@@ -0,0 +1,173 @@
+; Automatically generated by SBV. Do not edit.
+(set-option :produce-models true)
+(set-logic QF_UFBV)
+(set-info :status sat)
+; --- uninterpreted sorts ---
+; --- literal constants ---
+(define-fun s_2 () Bool false)
+(define-fun s_1 () Bool true)
+(define-fun s77 () (_ BitVec 8) #x00)
+(define-fun s78 () (_ BitVec 8) #x04)
+(define-fun s81 () (_ BitVec 8) #x01)
+(define-fun s83 () (_ BitVec 8) #xff)
+; --- skolem constants ---
+(declare-fun s0 () (_ BitVec 8))
+(declare-fun s1 () (_ BitVec 8))
+(declare-fun s2 () (_ BitVec 8))
+(declare-fun s3 () Bool)
+(declare-fun s4 () (_ BitVec 8))
+(declare-fun s5 () Bool)
+(declare-fun s6 () (_ BitVec 8))
+(declare-fun s7 () Bool)
+(declare-fun s8 () (_ BitVec 8))
+(declare-fun s9 () Bool)
+(declare-fun s10 () (_ BitVec 8))
+(declare-fun s11 () Bool)
+(declare-fun s12 () (_ BitVec 8))
+(declare-fun s13 () Bool)
+(declare-fun s14 () (_ BitVec 8))
+(declare-fun s15 () Bool)
+(declare-fun s16 () (_ BitVec 8))
+(declare-fun s17 () Bool)
+(declare-fun s18 () (_ BitVec 8))
+(declare-fun s19 () Bool)
+(declare-fun s20 () (_ BitVec 8))
+(declare-fun s21 () Bool)
+(declare-fun s22 () (_ BitVec 8))
+(declare-fun s23 () Bool)
+(declare-fun s24 () (_ BitVec 8))
+(declare-fun s25 () Bool)
+(declare-fun s26 () (_ BitVec 8))
+(declare-fun s27 () Bool)
+(declare-fun s28 () (_ BitVec 8))
+(declare-fun s29 () Bool)
+(declare-fun s30 () (_ BitVec 8))
+(declare-fun s31 () Bool)
+(declare-fun s32 () (_ BitVec 8))
+(declare-fun s33 () Bool)
+(declare-fun s34 () (_ BitVec 8))
+(declare-fun s35 () Bool)
+(declare-fun s36 () (_ BitVec 8))
+(declare-fun s37 () Bool)
+(declare-fun s38 () (_ BitVec 8))
+(declare-fun s39 () Bool)
+(declare-fun s40 () (_ BitVec 8))
+(declare-fun s41 () Bool)
+(declare-fun s42 () (_ BitVec 8))
+; --- constant tables ---
+; --- skolemized tables ---
+(declare-fun table0 ((_ BitVec 8)) (_ BitVec 8))
+(declare-fun table1 ((_ BitVec 8)) Bool)
+(declare-fun table2 ((_ BitVec 8)) (_ BitVec 8))
+(declare-fun table3 ((_ BitVec 8)) Bool)
+; --- arrays ---
+; --- uninterpreted constants ---
+; --- user given axioms ---
+; --- formula ---
+(assert ; no quantifiers
+ (let ((s43 (and s3 s5)))
+ (let ((s44 (or s3 s5)))
+ (let ((s45 (not s44)))
+ (let ((s46 (= (bvcomp s4 s6) #b1)))
+ (let ((s47 (and s45 s46)))
+ (let ((s48 (or s43 s47)))
+ (let ((s49 (and s11 s13)))
+ (let ((s50 (or s11 s13)))
+ (let ((s51 (not s50)))
+ (let ((s52 (= (bvcomp s12 s14) #b1)))
+ (let ((s53 (and s51 s52)))
+ (let ((s54 (or s49 s53)))
+ (let ((s55 (and s19 s21)))
+ (let ((s56 (or s19 s21)))
+ (let ((s57 (not s56)))
+ (let ((s58 (= (bvcomp s20 s22) #b1)))
+ (let ((s59 (and s57 s58)))
+ (let ((s60 (or s55 s59)))
+ (let ((s61 (and s27 s29)))
+ (let ((s62 (or s27 s29)))
+ (let ((s63 (not s62)))
+ (let ((s64 (= (bvcomp s28 s30) #b1)))
+ (let ((s65 (and s63 s64)))
+ (let ((s66 (or s61 s65)))
+ (let ((s67 (and s35 s37)))
+ (let ((s68 (or s35 s37)))
+ (let ((s69 (not s68)))
+ (let ((s70 (= (bvcomp s36 s38) #b1)))
+ (let ((s71 (and s69 s70)))
+ (let ((s72 (or s67 s71)))
+ (let ((s73 (and s66 s72)))
+ (let ((s74 (and s60 s73)))
+ (let ((s75 (and s54 s74)))
+ (let ((s76 (and s48 s75)))
+ (let ((s79 (bvurem s0 s78)))
+ (let ((s80 (not (= (bvcomp s77 s79) #b1))))
+ (let ((s82 (ite s80 s81 s77)))
+ (let ((s84 (= (bvcomp s82 s83) #b1)))
+ (let ((s85 (bvadd s78 s79)))
+ (let ((s86 (ite s84 s85 s79)))
+ (let ((s87 (ite (bvule #x04 s86) s77 (table0 s86))))
+ (let ((s88 (= (bvcomp s8 s87) #b1)))
+ (let ((s89 (ite (bvule #x04 s86) s_2 (table1 s86))))
+ (let ((s90 (= s7 s89)))
+ (let ((s91 (ite (bvule #x04 s86) s77 (table2 s86))))
+ (let ((s92 (= (bvcomp s10 s91) #b1)))
+ (let ((s93 (ite (bvule #x04 s86) s_2 (table3 s86))))
+ (let ((s94 (= s9 s93)))
+ (let ((s95 (and s92 s94)))
+ (let ((s96 (and s90 s95)))
+ (let ((s97 (and s88 s96)))
+ (let ((s98 (and s7 s9)))
+ (let ((s99 (or s7 s9)))
+ (let ((s100 (not s99)))
+ (let ((s101 (= (bvcomp s8 s10) #b1)))
+ (let ((s102 (and s100 s101)))
+ (let ((s103 (or s98 s102)))
+ (let ((s104 (and s15 s17)))
+ (let ((s105 (or s15 s17)))
+ (let ((s106 (not s105)))
+ (let ((s107 (= (bvcomp s16 s18) #b1)))
+ (let ((s108 (and s106 s107)))
+ (let ((s109 (or s104 s108)))
+ (let ((s110 (and s23 s25)))
+ (let ((s111 (or s23 s25)))
+ (let ((s112 (not s111)))
+ (let ((s113 (= (bvcomp s24 s26) #b1)))
+ (let ((s114 (and s112 s113)))
+ (let ((s115 (or s110 s114)))
+ (let ((s116 (and s31 s33)))
+ (let ((s117 (or s31 s33)))
+ (let ((s118 (not s117)))
+ (let ((s119 (= (bvcomp s32 s34) #b1)))
+ (let ((s120 (and s118 s119)))
+ (let ((s121 (or s116 s120)))
+ (let ((s122 (and s39 s41)))
+ (let ((s123 (or s39 s41)))
+ (let ((s124 (not s123)))
+ (let ((s125 (= (bvcomp s40 s42) #b1)))
+ (let ((s126 (and s124 s125)))
+ (let ((s127 (or s122 s126)))
+ (let ((s128 (and s121 s127)))
+ (let ((s129 (and s115 s128)))
+ (let ((s130 (and s109 s129)))
+ (let ((s131 (and s103 s130)))
+ (let ((s132 (not s131)))
+ (let ((s133 (and s97 s132)))
+ (let ((s134 (and s76 s133)))
+ (and (= (table0 #x00) s12)
+ (= (table0 #x01) s20)
+ (= (table0 #x02) s28)
+ (= (table0 #x03) s36)
+ (= (table1 #x00) s11)
+ (= (table1 #x01) s19)
+ (= (table1 #x02) s27)
+ (= (table1 #x03) s35)
+ (= (table2 #x00) s14)
+ (= (table2 #x01) s22)
+ (= (table2 #x02) s30)
+ (= (table2 #x03) s38)
+ (= (table3 #x00) s13)
+ (= (table3 #x01) s21)
+ (= (table3 #x02) s29)
+ (= (table3 #x03) s37)
+ s134))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+(check-sat)
diff --git a/test/regress/regress0/bug521.minimized.smt2 b/test/regress/regress0/bug521.minimized.smt2
new file mode 100644
index 000000000..6751d4077
--- /dev/null
+++ b/test/regress/regress0/bug521.minimized.smt2
@@ -0,0 +1,15 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(declare-fun _substvar_301_ () Bool)
+(declare-fun _substvar_300_ () Bool)
+(declare-fun group_size_x () (_ BitVec 32))
+(declare-fun _WRITE_OFFSET_$$p$1@1 () (_ BitVec 32))
+(declare-fun inline$_LOG_WRITE_$$p$1$_offset$1@0 () (_ BitVec 32))
+(declare-fun _WRITE_OFFSET_$$p$1@0 () (_ BitVec 32))
+(declare-fun group_id_x$1 () (_ BitVec 32))
+(declare-fun local_id_x$1 () (_ BitVec 32))
+(declare-fun inline$_LOG_WRITE_$$p$0$_offset$1@0 () (_ BitVec 32))
+(define-fun $foo () Bool (=> true (let ((inline$_LOG_WRITE_$$p$1$_LOG_WRITE_correct (=> true (=> true (=> (= _WRITE_OFFSET_$$p$1@1 (ite _substvar_300_ inline$_LOG_WRITE_$$p$1$_offset$1@0 _WRITE_OFFSET_$$p$1@0)) false))))) (let ((inline$_LOG_WRITE_$$p$1$Entry_correct (=> true (=> (= inline$_LOG_WRITE_$$p$1$_offset$1@0 (bvadd (bvadd (bvmul group_size_x group_id_x$1) local_id_x$1) #x00000001)) (=> true inline$_LOG_WRITE_$$p$1$_LOG_WRITE_correct))))) (let ((inline$$bugle_barrier$0$anon1_Else_correct (=> true (=> true (=> true inline$_LOG_WRITE_$$p$1$Entry_correct))))) (let ((inline$$bugle_barrier$0$Entry_correct (=> true (and _substvar_301_ (=> true (=> true inline$$bugle_barrier$0$anon1_Else_correct)))))) (let (($0$1_correct (=> true (=> true (=> true (=> true (=> true (=> true (=> true (=> true (=> true (=> true inline$$bugle_barrier$0$Entry_correct)))))))))))) (let ((inline$_LOG_WRITE_$$p$0$_LOG_WRITE_correct (=> true (=> true (=> (= _WRITE_OFFSET_$$p$1@0 inline$_LOG_WRITE_$$p$0$_offset$1@0) $0$1_correct))))) (let ((inline$_LOG_WRITE_$$p$0$Entry_correct (=> true (=> (= inline$_LOG_WRITE_$$p$0$_offset$1@0 (bvadd (bvmul group_size_x group_id_x$1) local_id_x$1)) (=> true inline$_LOG_WRITE_$$p$0$_LOG_WRITE_correct))))) (let (($0_correct (=> true (=> true (=> true inline$_LOG_WRITE_$$p$0$Entry_correct))))) $0_correct))))))))))
+(assert (not (=> true $foo)))
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/bug521.smt2 b/test/regress/regress0/bug521.smt2
new file mode 100644
index 000000000..8f840a1f6
--- /dev/null
+++ b/test/regress/regress0/bug521.smt2
@@ -0,0 +1,323 @@
+;(set-option :produce-unsat-cores true)
+(set-option :incremental true)
+(set-option :print-success false)
+(set-info :smt-lib-version 2.0)
+(set-info :status sat)
+(set-option :produce-models true)
+(set-logic ALL_SUPPORTED)
+; done setting options
+
+; Boogie universal background predicate
+; Copyright (c) 2004-2010, Microsoft Corp.
+(set-info :category "industrial")
+(declare-sort |T@U| 0)
+(declare-sort |T@T| 0)
+(declare-fun real_pow (Real Real) Real)
+(declare-fun UOrdering2 (|T@U| |T@U|) Bool)
+(declare-fun UOrdering3 (|T@T| |T@U| |T@U|) Bool)
+
+(declare-fun group_size_y () (_ BitVec 32))
+(declare-fun group_size_z () (_ BitVec 32))
+(declare-fun num_groups_y () (_ BitVec 32))
+(declare-fun num_groups_z () (_ BitVec 32))
+(declare-fun group_size_x () (_ BitVec 32))
+(declare-fun num_groups_x () (_ BitVec 32))
+(declare-fun ControlFlow (Int Int) Int)
+(declare-fun %lbl%+1458 () Bool)
+(declare-fun %lbl%@3203 () Bool)
+(declare-fun _WRITE_HAS_OCCURRED_$$p$1@2 () Bool)
+(declare-fun _WRITE_SOURCE_$$p$1@2 () (_ BitVec 32))
+(declare-fun %lbl%@3213 () Bool)
+(declare-fun _READ_HAS_OCCURRED_$$p$1 () Bool)
+(declare-fun _READ_SOURCE_$$p$1 () (_ BitVec 32))
+(declare-fun %lbl%@3225 () Bool)
+(declare-fun %lbl%@3240 () Bool)
+(declare-fun %lbl%+1440 () Bool)
+(declare-fun $mv_state (Int Int) Bool)
+(declare-fun $mv_state_const () Int)
+(declare-fun call465formal@_offset$2@0 () (_ BitVec 32))
+(declare-fun group_id_x$2 () (_ BitVec 32))
+(declare-fun local_id_x$2 () (_ BitVec 32))
+(declare-fun call465formal@_value$2@0 () (_ BitVec 32))
+(declare-fun %lbl%@3060 () Bool)
+(declare-fun _WRITE_HAS_OCCURRED_$$p$1@1 () Bool)
+(declare-fun _WRITE_OFFSET_$$p$1@1 () (_ BitVec 32))
+(declare-fun _WRITE_VALUE_$$p$1@1 () (_ BitVec 32))
+(declare-fun %lbl%@3078 () Bool)
+(declare-fun _READ_OFFSET_$$p$1 () (_ BitVec 32))
+(declare-fun _READ_VALUE_$$p$1 () (_ BitVec 32))
+(declare-fun %lbl%@3099 () Bool)
+(declare-fun _WRITE_SOURCE_$$p$1@1 () (_ BitVec 32))
+(declare-fun %lbl%@3109 () Bool)
+(declare-fun %lbl%@3121 () Bool)
+(declare-fun %lbl%@3136 () Bool)
+(declare-fun %lbl%+1434 () Bool)
+(declare-fun inline$_LOG_WRITE_$$p$1$track@1 () Bool)
+(declare-fun _WRITE_HAS_OCCURRED_$$p$1@0 () Bool)
+(declare-fun inline$_LOG_WRITE_$$p$1$_offset$1@0 () (_ BitVec 32))
+(declare-fun _WRITE_OFFSET_$$p$1@0 () (_ BitVec 32))
+(declare-fun inline$_LOG_WRITE_$$p$1$_value$1@0 () (_ BitVec 32))
+(declare-fun _WRITE_VALUE_$$p$1@0 () (_ BitVec 32))
+(declare-fun _WRITE_SOURCE_$$p$1@0 () (_ BitVec 32))
+(declare-fun %lbl%+1432 () Bool)
+(declare-fun group_id_x$1 () (_ BitVec 32))
+(declare-fun local_id_x$1 () (_ BitVec 32))
+(declare-fun %lbl%+1328 () Bool)
+(declare-fun group_id_y$1 () (_ BitVec 32))
+(declare-fun group_id_y$2 () (_ BitVec 32))
+(declare-fun group_id_z$1 () (_ BitVec 32))
+(declare-fun group_id_z$2 () (_ BitVec 32))
+(declare-fun %lbl%+1330 () Bool)
+(declare-fun %lbl%+1324 () Bool)
+(declare-fun %lbl%@2798 () Bool)
+(declare-fun %lbl%+1334 () Bool)
+(declare-fun call397formal@_offset$2@0 () (_ BitVec 32))
+(declare-fun call397formal@_value$2@0 () (_ BitVec 32))
+(declare-fun %lbl%@2667 () Bool)
+(declare-fun %lbl%@2685 () Bool)
+(declare-fun %lbl%@2706 () Bool)
+(declare-fun %lbl%@2716 () Bool)
+(declare-fun %lbl%@2728 () Bool)
+(declare-fun %lbl%@2743 () Bool)
+(declare-fun %lbl%+1189 () Bool)
+(declare-fun inline$_LOG_WRITE_$$p$0$track@1 () Bool)
+(declare-fun _WRITE_HAS_OCCURRED_$$p$1 () Bool)
+(declare-fun inline$_LOG_WRITE_$$p$0$_offset$1@0 () (_ BitVec 32))
+(declare-fun _WRITE_OFFSET_$$p$1 () (_ BitVec 32))
+(declare-fun inline$_LOG_WRITE_$$p$0$_value$1@0 () (_ BitVec 32))
+(declare-fun _WRITE_VALUE_$$p$1 () (_ BitVec 32))
+(declare-fun _WRITE_SOURCE_$$p$1 () (_ BitVec 32))
+(declare-fun %lbl%+1187 () Bool)
+(declare-fun %lbl%+1462 () Bool)
+(declare-fun local_id_y$1 () (_ BitVec 32))
+(declare-fun local_id_y$2 () (_ BitVec 32))
+(declare-fun local_id_z$1 () (_ BitVec 32))
+(declare-fun local_id_z$2 () (_ BitVec 32))
+(assert (not (= (ite (= group_size_y #x00000001) #b1 #b0) #b0)))
+(assert (not (= (ite (= group_size_z #x00000001) #b1 #b0) #b0)))
+(assert (not (= (ite (= num_groups_y #x00000001) #b1 #b0) #b0)))
+(assert (not (= (ite (= num_groups_z #x00000001) #b1 #b0) #b0)))
+(assert (not (= (ite (= group_size_x #x00000400) #b1 #b0) #b0)))
+(assert (not (= (ite (= num_groups_x #x00000400) #b1 #b0) #b0)))
+(define-fun $foo () Bool (=> (= (ControlFlow 0 0) 1462) (let ((GeneratedUnifiedExit_correct (=> (and %lbl%+1458 true) (and
+(or %lbl%@3203 (=> (= (ControlFlow 0 1458) (- 0 3203)) (=> (not _WRITE_HAS_OCCURRED_$$p$1@2) (= _WRITE_SOURCE_$$p$1@2 #x00000000))))
+(=> (=> (not _WRITE_HAS_OCCURRED_$$p$1@2) (= _WRITE_SOURCE_$$p$1@2 #x00000000)) (and
+(or %lbl%@3213 (=> (= (ControlFlow 0 1458) (- 0 3213)) (=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000))))
+(=> (=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000)) (and
+(or %lbl%@3225 (=> (= (ControlFlow 0 1458) (- 0 3225)) (=> _WRITE_HAS_OCCURRED_$$p$1@2 (or
+(= _WRITE_SOURCE_$$p$1@2 #x00000001)
+(= _WRITE_SOURCE_$$p$1@2 #x00000002)))))
+(=> (=> _WRITE_HAS_OCCURRED_$$p$1@2 (or
+(= _WRITE_SOURCE_$$p$1@2 #x00000001)
+(= _WRITE_SOURCE_$$p$1@2 #x00000002))) (and
+(or %lbl%@3240 (=> (= (ControlFlow 0 1458) (- 0 3240)) (=> _READ_HAS_OCCURRED_$$p$1 false)))
+(=> (=> _READ_HAS_OCCURRED_$$p$1 false) true)))))))))))
+(let (($0$3_correct (=> (and %lbl%+1440 true) (=> (and
+($mv_state $mv_state_const 1)
+true
+(= call465formal@_offset$2@0 (bvadd (bvadd (bvmul group_size_x group_id_x$2) local_id_x$2) #x00000001))
+(= call465formal@_value$2@0 (bvadd (bvmul group_size_x group_id_x$2) local_id_x$2))) (and
+(or %lbl%@3060 (=> (= (ControlFlow 0 1440) (- 0 3060)) (not (and
+true
+_WRITE_HAS_OCCURRED_$$p$1@1
+(= _WRITE_OFFSET_$$p$1@1 call465formal@_offset$2@0)
+(not (= _WRITE_VALUE_$$p$1@1 call465formal@_value$2@0))))))
+(=> (not (and
+true
+_WRITE_HAS_OCCURRED_$$p$1@1
+(= _WRITE_OFFSET_$$p$1@1 call465formal@_offset$2@0)
+(not (= _WRITE_VALUE_$$p$1@1 call465formal@_value$2@0)))) (and
+(or %lbl%@3078 (=> (= (ControlFlow 0 1440) (- 0 3078)) (not (and
+true
+_READ_HAS_OCCURRED_$$p$1
+(= _READ_OFFSET_$$p$1 call465formal@_offset$2@0)
+(not (= _READ_VALUE_$$p$1 call465formal@_value$2@0))))))
+(=> (not (and
+true
+_READ_HAS_OCCURRED_$$p$1
+(= _READ_OFFSET_$$p$1 call465formal@_offset$2@0)
+(not (= _READ_VALUE_$$p$1 call465formal@_value$2@0)))) (and
+(or %lbl%@3099 (=> (= (ControlFlow 0 1440) (- 0 3099)) (=> (not _WRITE_HAS_OCCURRED_$$p$1@1) (= _WRITE_SOURCE_$$p$1@1 #x00000000))))
+(=> (=> (not _WRITE_HAS_OCCURRED_$$p$1@1) (= _WRITE_SOURCE_$$p$1@1 #x00000000)) (and
+(or %lbl%@3109 (=> (= (ControlFlow 0 1440) (- 0 3109)) (=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000))))
+(=> (=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000)) (and
+(or %lbl%@3121 (=> (= (ControlFlow 0 1440) (- 0 3121)) (=> _WRITE_HAS_OCCURRED_$$p$1@1 (or
+(= _WRITE_SOURCE_$$p$1@1 #x00000001)
+(= _WRITE_SOURCE_$$p$1@1 #x00000002)))))
+(=> (=> _WRITE_HAS_OCCURRED_$$p$1@1 (or
+(= _WRITE_SOURCE_$$p$1@1 #x00000001)
+(= _WRITE_SOURCE_$$p$1@1 #x00000002))) (and
+(or %lbl%@3136 (=> (= (ControlFlow 0 1440) (- 0 3136)) (=> _READ_HAS_OCCURRED_$$p$1 false)))
+(=> (=> _READ_HAS_OCCURRED_$$p$1 false) (=> (=> (not _WRITE_HAS_OCCURRED_$$p$1@1) (= _WRITE_SOURCE_$$p$1@1 #x00000000)) (=> (and
+(=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000))
+(=> _WRITE_HAS_OCCURRED_$$p$1@1 (or
+(= _WRITE_SOURCE_$$p$1@1 #x00000001)
+(= _WRITE_SOURCE_$$p$1@1 #x00000002)))) (=> (and
+(=> _READ_HAS_OCCURRED_$$p$1 false)
+(= _WRITE_HAS_OCCURRED_$$p$1@2 _WRITE_HAS_OCCURRED_$$p$1@1)
+(= _WRITE_SOURCE_$$p$1@2 _WRITE_SOURCE_$$p$1@1)
+(= (ControlFlow 0 1440) 1458)) GeneratedUnifiedExit_correct)))))))))))))))))))
+(let ((inline$_LOG_WRITE_$$p$1$_LOG_WRITE_correct (=> (and %lbl%+1434 true) (=> (= _WRITE_HAS_OCCURRED_$$p$1@1 (ite (and
+true
+inline$_LOG_WRITE_$$p$1$track@1) true _WRITE_HAS_OCCURRED_$$p$1@0)) (=> (and
+(= _WRITE_OFFSET_$$p$1@1 (ite (and
+true
+inline$_LOG_WRITE_$$p$1$track@1) inline$_LOG_WRITE_$$p$1$_offset$1@0 _WRITE_OFFSET_$$p$1@0))
+(= _WRITE_VALUE_$$p$1@1 (ite (and
+true
+inline$_LOG_WRITE_$$p$1$track@1) inline$_LOG_WRITE_$$p$1$_value$1@0 _WRITE_VALUE_$$p$1@0))
+(= _WRITE_SOURCE_$$p$1@1 (ite (and
+true
+inline$_LOG_WRITE_$$p$1$track@1) #x00000002 _WRITE_SOURCE_$$p$1@0))
+(= (ControlFlow 0 1434) 1440)) $0$3_correct)))))
+(let ((inline$_LOG_WRITE_$$p$1$Entry_correct (=> (and %lbl%+1432 true) (=> (= inline$_LOG_WRITE_$$p$1$_offset$1@0 (bvadd (bvadd (bvmul group_size_x group_id_x$1) local_id_x$1) #x00000001)) (=> (and
+(= inline$_LOG_WRITE_$$p$1$_value$1@0 (bvadd (bvmul group_size_x group_id_x$1) local_id_x$1))
+(= (ControlFlow 0 1432) 1434)) inline$_LOG_WRITE_$$p$1$_LOG_WRITE_correct)))))
+(let ((inline$$bugle_barrier$0$anon1_Else_correct (=> (and %lbl%+1328 true) (=> (=> (and
+(= group_id_x$1 group_id_x$2)
+(= group_id_y$1 group_id_y$2)
+(= group_id_z$1 group_id_z$2)) (=> (= #b1 #b1) (not _READ_HAS_OCCURRED_$$p$1))) (=> (and
+(=> (and
+(= group_id_x$1 group_id_x$2)
+(= group_id_y$1 group_id_y$2)
+(= group_id_z$1 group_id_z$2)) (=> (= #b1 #b1) (not _WRITE_HAS_OCCURRED_$$p$1@0)))
+(= (ControlFlow 0 1328) 1432)) inline$_LOG_WRITE_$$p$1$Entry_correct)))))
+(let ((inline$$bugle_barrier$0$anon1_Then_correct (=> (and %lbl%+1330 true) true)))
+(let ((inline$$bugle_barrier$0$Entry_correct (=> (and %lbl%+1324 true) (and
+(or %lbl%@2798 (=> (= (ControlFlow 0 1324) (- 0 2798)) (=> (and
+(= group_id_x$1 group_id_x$2)
+(= group_id_y$1 group_id_y$2)
+(= group_id_z$1 group_id_z$2)) (= true true))))
+(=> (=> (and
+(= group_id_x$1 group_id_x$2)
+(= group_id_y$1 group_id_y$2)
+(= group_id_z$1 group_id_z$2)) (= true true)) (and
+(=> (= (ControlFlow 0 1324) 1330) inline$$bugle_barrier$0$anon1_Then_correct)
+(=> (= (ControlFlow 0 1324) 1328) inline$$bugle_barrier$0$anon1_Else_correct)))))))
+(let (($0$1_correct (=> (and %lbl%+1334 true) (=> (and
+($mv_state $mv_state_const 0)
+true
+(= call397formal@_offset$2@0 (bvadd (bvmul group_size_x group_id_x$2) local_id_x$2))
+(= call397formal@_value$2@0 (bvadd (bvmul group_size_x group_id_x$2) local_id_x$2))) (and
+(or %lbl%@2667 (=> (= (ControlFlow 0 1334) (- 0 2667)) (not (and
+true
+_WRITE_HAS_OCCURRED_$$p$1@0
+(= _WRITE_OFFSET_$$p$1@0 call397formal@_offset$2@0)
+(not (= _WRITE_VALUE_$$p$1@0 call397formal@_value$2@0))))))
+(=> (not (and
+true
+_WRITE_HAS_OCCURRED_$$p$1@0
+(= _WRITE_OFFSET_$$p$1@0 call397formal@_offset$2@0)
+(not (= _WRITE_VALUE_$$p$1@0 call397formal@_value$2@0)))) (and
+(or %lbl%@2685 (=> (= (ControlFlow 0 1334) (- 0 2685)) (not (and
+true
+_READ_HAS_OCCURRED_$$p$1
+(= _READ_OFFSET_$$p$1 call397formal@_offset$2@0)
+(not (= _READ_VALUE_$$p$1 call397formal@_value$2@0))))))
+(=> (not (and
+true
+_READ_HAS_OCCURRED_$$p$1
+(= _READ_OFFSET_$$p$1 call397formal@_offset$2@0)
+(not (= _READ_VALUE_$$p$1 call397formal@_value$2@0)))) (and
+(or %lbl%@2706 (=> (= (ControlFlow 0 1334) (- 0 2706)) (=> (not _WRITE_HAS_OCCURRED_$$p$1@0) (= _WRITE_SOURCE_$$p$1@0 #x00000000))))
+(=> (=> (not _WRITE_HAS_OCCURRED_$$p$1@0) (= _WRITE_SOURCE_$$p$1@0 #x00000000)) (and
+(or %lbl%@2716 (=> (= (ControlFlow 0 1334) (- 0 2716)) (=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000))))
+(=> (=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000)) (and
+(or %lbl%@2728 (=> (= (ControlFlow 0 1334) (- 0 2728)) (=> _WRITE_HAS_OCCURRED_$$p$1@0 (or
+(= _WRITE_SOURCE_$$p$1@0 #x00000001)
+(= _WRITE_SOURCE_$$p$1@0 #x00000002)))))
+(=> (=> _WRITE_HAS_OCCURRED_$$p$1@0 (or
+(= _WRITE_SOURCE_$$p$1@0 #x00000001)
+(= _WRITE_SOURCE_$$p$1@0 #x00000002))) (and
+(or %lbl%@2743 (=> (= (ControlFlow 0 1334) (- 0 2743)) (=> _READ_HAS_OCCURRED_$$p$1 false)))
+(=> (=> _READ_HAS_OCCURRED_$$p$1 false) (=> (=> (not _WRITE_HAS_OCCURRED_$$p$1@0) (= _WRITE_SOURCE_$$p$1@0 #x00000000)) (=> (and
+(=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000))
+(=> _WRITE_HAS_OCCURRED_$$p$1@0 (or
+(= _WRITE_SOURCE_$$p$1@0 #x00000001)
+(= _WRITE_SOURCE_$$p$1@0 #x00000002)))
+(=> _READ_HAS_OCCURRED_$$p$1 false)
+(= (ControlFlow 0 1334) 1324)) inline$$bugle_barrier$0$Entry_correct))))))))))))))))))
+(let ((inline$_LOG_WRITE_$$p$0$_LOG_WRITE_correct (=> (and %lbl%+1189 true) (=> (= _WRITE_HAS_OCCURRED_$$p$1@0 (ite (and
+true
+inline$_LOG_WRITE_$$p$0$track@1) true _WRITE_HAS_OCCURRED_$$p$1)) (=> (and
+(= _WRITE_OFFSET_$$p$1@0 (ite (and
+true
+inline$_LOG_WRITE_$$p$0$track@1) inline$_LOG_WRITE_$$p$0$_offset$1@0 _WRITE_OFFSET_$$p$1))
+(= _WRITE_VALUE_$$p$1@0 (ite (and
+true
+inline$_LOG_WRITE_$$p$0$track@1) inline$_LOG_WRITE_$$p$0$_value$1@0 _WRITE_VALUE_$$p$1))
+(= _WRITE_SOURCE_$$p$1@0 (ite (and
+true
+inline$_LOG_WRITE_$$p$0$track@1) #x00000001 _WRITE_SOURCE_$$p$1))
+(= (ControlFlow 0 1189) 1334)) $0$1_correct)))))
+(let ((inline$_LOG_WRITE_$$p$0$Entry_correct (=> (and %lbl%+1187 true) (=> (= inline$_LOG_WRITE_$$p$0$_offset$1@0 (bvadd (bvmul group_size_x group_id_x$1) local_id_x$1)) (=> (and
+(= inline$_LOG_WRITE_$$p$0$_value$1@0 (bvadd (bvmul group_size_x group_id_x$1) local_id_x$1))
+(= (ControlFlow 0 1187) 1189)) inline$_LOG_WRITE_$$p$0$_LOG_WRITE_correct)))))
+(let (($0_correct (=> (and %lbl%+1462 true) (=> (and
+(not _READ_HAS_OCCURRED_$$p$1)
+(not _WRITE_HAS_OCCURRED_$$p$1)
+(= _READ_SOURCE_$$p$1 #x00000000)
+(= _WRITE_SOURCE_$$p$1 #x00000000)
+(bvsgt group_size_x #x00000000)
+(bvsgt num_groups_x #x00000000)
+(bvsge group_id_x$1 #x00000000)
+(bvsge group_id_x$2 #x00000000)) (=> (and
+(bvslt group_id_x$1 num_groups_x)
+(bvslt group_id_x$2 num_groups_x)
+(bvsge local_id_x$1 #x00000000)
+(bvsge local_id_x$2 #x00000000)
+(bvslt local_id_x$1 group_size_x)
+(bvslt local_id_x$2 group_size_x)
+(bvsgt group_size_y #x00000000)
+(bvsgt num_groups_y #x00000000)
+(bvsge group_id_y$1 #x00000000)
+(bvsge group_id_y$2 #x00000000)
+(bvslt group_id_y$1 num_groups_y)
+(bvslt group_id_y$2 num_groups_y)
+(bvsge local_id_y$1 #x00000000)
+(bvsge local_id_y$2 #x00000000)
+(bvslt local_id_y$1 group_size_y)
+(bvslt local_id_y$2 group_size_y)
+(bvsgt group_size_z #x00000000)
+(bvsgt num_groups_z #x00000000)
+(bvsge group_id_z$1 #x00000000)
+(bvsge group_id_z$2 #x00000000)
+(bvslt group_id_z$1 num_groups_z)
+(bvslt group_id_z$2 num_groups_z)
+(bvsge local_id_z$1 #x00000000)
+(bvsge local_id_z$2 #x00000000)
+(bvslt local_id_z$1 group_size_z)
+(bvslt local_id_z$2 group_size_z)
+(=> (not _WRITE_HAS_OCCURRED_$$p$1) (= _WRITE_SOURCE_$$p$1 #x00000000))
+(=> (not _READ_HAS_OCCURRED_$$p$1) (= _READ_SOURCE_$$p$1 #x00000000))
+(=> _WRITE_HAS_OCCURRED_$$p$1 (or
+(= _WRITE_SOURCE_$$p$1 #x00000001)
+(= _WRITE_SOURCE_$$p$1 #x00000002)))
+(=> _READ_HAS_OCCURRED_$$p$1 false)
+(=> (and
+(= group_id_x$1 group_id_x$2)
+(= group_id_y$1 group_id_y$2)
+(= group_id_z$1 group_id_z$2)) (or
+(not (= local_id_x$1 local_id_x$2))
+(not (= local_id_y$1 local_id_y$2))
+(not (= local_id_z$1 local_id_z$2))))
+(= (ControlFlow 0 1462) 1187)) inline$_LOG_WRITE_$$p$0$Entry_correct)))))
+$0_correct)))))))))))))
+(push 1)
+(set-info :boogie-vc-id $foo)
+(assert (not
+(=> true $foo)
+))
+(check-sat)
+;(get-value ((ControlFlow 0 0)))
+; (get-value ((ControlFlow 0 1462)))
+; (get-value ((ControlFlow 0 1187)))
+; (get-value ((ControlFlow 0 1189)))
+; (get-value ((ControlFlow 0 1334)))
+; (get-value ((ControlFlow 0 1324)))
+; (get-value ((ControlFlow 0 1328)))
+; (get-value ((ControlFlow 0 1432)))
+; (get-value ((ControlFlow 0 1434)))
+; (get-value ((ControlFlow 0 1440)))
+; (get-model)
+; (assert (not (= (ControlFlow 0 1440) (- 3060))))
diff --git a/test/regress/regress0/bug522.smt2 b/test/regress/regress0/bug522.smt2
new file mode 100644
index 000000000..7c47c5fd6
--- /dev/null
+++ b/test/regress/regress0/bug522.smt2
@@ -0,0 +1,15 @@
+; EXPECT: sat
+; EXPECT: sat
+; EXIT: 10
+(set-option :incremental "true")
+(set-logic QF_UF)
+
+(push 1)
+(declare-sort U 0)
+(declare-fun x () U)
+(declare-fun y () U)
+(assert (= x y))
+(check-sat)
+(pop 1)
+
+(check-sat)
diff --git a/test/regress/regress0/bv/Makefile.am b/test/regress/regress0/bv/Makefile.am
index dbd9547a9..f0bfb2842 100644
--- a/test/regress/regress0/bv/Makefile.am
+++ b/test/regress/regress0/bv/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = . core
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/bv/core/Makefile.am b/test/regress/regress0/bv/core/Makefile.am
index 53cdadc4f..888e9d8dc 100644
--- a/test/regress/regress0/bv/core/Makefile.am
+++ b/test/regress/regress0/bv/core/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/chained-equality.smt2 b/test/regress/regress0/chained-equality.smt2
new file mode 100644
index 000000000..fb3a25b94
--- /dev/null
+++ b/test/regress/regress0/chained-equality.smt2
@@ -0,0 +1,10 @@
+(set-option :produce-models true)
+(set-info :status unsat)
+(set-logic QF_UF)
+(declare-fun x () Bool)
+(declare-fun y () Bool)
+(declare-fun z () Bool)
+(assert (= x y z))
+(assert (not x))
+(assert z)
+(check-sat)
diff --git a/test/regress/regress0/datatypes/Makefile.am b/test/regress/regress0/datatypes/Makefile.am
index 06227ad3a..31999b203 100644
--- a/test/regress/regress0/datatypes/Makefile.am
+++ b/test/regress/regress0/datatypes/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -30,9 +34,9 @@ TESTS = \
datatype3.cvc \
datatype4.cvc \
datatype13.cvc \
+ empty_tuprec.cvc \
mutually-recursive.cvc \
rewriter.cvc \
- typed_v1l50016-simp.cvc \
typed_v10l30054.cvc \
typed_v1l80005.cvc \
typed_v2l30079.cvc \
diff --git a/test/regress/regress0/datatypes/empty_tuprec.cvc b/test/regress/regress0/datatypes/empty_tuprec.cvc
new file mode 100644
index 000000000..8e163e855
--- /dev/null
+++ b/test/regress/regress0/datatypes/empty_tuprec.cvc
@@ -0,0 +1,20 @@
+OPTION "incremental";
+
+a1, a2 : []; % empty tuples (a unit type)
+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
+QUERY a1 = a2;
+
+% EXPECT: valid
+QUERY b1 = b2;
+
+% EXPECT: valid
+QUERY c1 = c2;
+
+% EXPECT: valid
+QUERY d1 = d2;
+
+% EXIT: 20
diff --git a/test/regress/regress0/decision/Makefile.am b/test/regress/regress0/decision/Makefile.am
index 4bba7b049..0f8ef8e8e 100644
--- a/test/regress/regress0/decision/Makefile.am
+++ b/test/regress/regress0/decision/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -22,11 +26,11 @@ TESTS = \
quant-Arrays_Q1-noinfer.smt2 \
quant-ex1.smt2 \
quant-ex1.disable_miniscope.smt2 \
- uflia-error0.smt2 \
- uflia-xs-09-16-3-4-1-5.smt \
uflia-xs-09-16-3-4-1-5.delta03.smt \
aufbv-fuzz01.smt \
bug347.smt \
+ bug374a.smt \
+ bug374b.smt2 \
error20.smt \
error20.delta01.smt \
error122.smt \
@@ -36,24 +40,19 @@ TESTS = \
pp-regfile.delta01.smt \
pp-regfile.delta02.smt
-# Correct, but takes too long:
-# pp-regfile.smt \
-#
-
EXTRA_DIST = $(TESTS) \
aufbv-fuzz01.smt.expect \
pp-regfile.delta01.smt.expect \
- uflia-error0.smt2.expect \
bitvec0.delta01.smt.expect \
pp-regfile.delta02.smt.expect \
uflia-xs-09-16-3-4-1-5.delta03.smt.expect \
bitvec0.smt.expect \
- pp-regfile.smt.expect \
- uflia-xs-09-16-3-4-1-5.smt.expect \
bitvec5.smt.expect \
quant-Arrays_Q1-noinfer.smt2.expect \
wchains010ue.delta02.smt.expect \
bug347.smt.expect \
+ bug374a.smt.expect \
+ bug374b.smt2.expect \
quant-ex1.disable_miniscope.smt2.expect \
wchains010ue.smt.expect \
just_sat.expect \
diff --git a/test/regress/regress0/decision/bug374a.smt b/test/regress/regress0/decision/bug374a.smt
new file mode 100644
index 000000000..e338417c5
--- /dev/null
+++ b/test/regress/regress0/decision/bug374a.smt
@@ -0,0 +1,1197 @@
+(benchmark fuzzsmt
+:logic AUFLIA
+:status unknown
+:extrafuns ((f0 Int Int Int))
+:extrafuns ((f1 Array Array Array Array))
+:extrapreds ((p0 Int))
+:extrapreds ((p1 Array))
+:extrafuns ((v0 Int))
+:extrafuns ((v1 Array))
+:assumption
+(exists (?qvar0 Int) (?qvar1 Int) (?qvar2 Int)
+(flet ($qf0 (<= (f0 ?qvar1 ?qvar2) (f0 ?qvar0 ?qvar2)))
+$qf0
+))
+:formula
+(let (?e2 1)
+(let (?e3 0)
+(let (?e4 (ite (p0 v0) 1 0))
+(let (?e5 (* ?e3 v0))
+(let (?e6 (+ ?e5 ?e5))
+(let (?e7 (f0 ?e6 ?e4))
+(let (?e8 (~ v0))
+(let (?e9 (f0 ?e4 ?e5))
+(let (?e10 (f0 ?e6 ?e6))
+(let (?e11 (- ?e9 ?e7))
+(let (?e12 (+ ?e10 ?e7))
+(let (?e13 (ite (p0 ?e12) 1 0))
+(let (?e14 (* ?e3 ?e12))
+(let (?e15 (+ ?e8 ?e7))
+(let (?e16 (f0 ?e15 ?e10))
+(let (?e17 (* ?e15 ?e2))
+(let (?e18 (store v1 ?e12 ?e14))
+(let (?e19 (store v1 ?e8 ?e12))
+(let (?e20 (f1 v1 v1 v1))
+(let (?e21 (f1 ?e18 ?e20 ?e19))
+(flet ($e22 (p1 v1))
+(flet ($e23 (p1 ?e18))
+(flet ($e24 (p1 v1))
+(flet ($e25 (p1 ?e19))
+(flet ($e26 (p1 ?e20))
+(flet ($e27 (p1 ?e21))
+(flet ($e28 (<= ?e14 ?e16))
+(flet ($e29 (>= ?e4 v0))
+(flet ($e30 (< ?e13 ?e13))
+(flet ($e31 (<= ?e9 ?e6))
+(flet ($e32 (< ?e5 ?e13))
+(flet ($e33 (< ?e8 ?e11))
+(flet ($e34 (> ?e8 ?e9))
+(flet ($e35 (<= ?e7 ?e4))
+(flet ($e36 (distinct ?e13 ?e11))
+(flet ($e37 (distinct ?e17 ?e15))
+(flet ($e38 (= ?e8 ?e8))
+(flet ($e39 (distinct ?e16 ?e17))
+(flet ($e40 (= ?e12 ?e8))
+(flet ($e41 (distinct v0 ?e12))
+(flet ($e42 (= ?e11 ?e16))
+(flet ($e43 (< ?e10 ?e14))
+(flet ($e44 (> ?e17 ?e5))
+(flet ($e45 (distinct ?e11 ?e9))
+(flet ($e46 (> ?e14 v0))
+(flet ($e47 (<= v0 ?e7))
+(flet ($e48 (<= ?e13 ?e17))
+(flet ($e49 (> ?e13 ?e7))
+(flet ($e50 (> ?e17 v0))
+(flet ($e51 (>= ?e11 ?e14))
+(flet ($e52 (<= ?e14 ?e13))
+(flet ($e53 (<= ?e8 ?e6))
+(flet ($e54 (<= v0 ?e16))
+(flet ($e55 (distinct ?e6 v0))
+(flet ($e56 (> ?e7 ?e10))
+(flet ($e57 (distinct ?e11 ?e13))
+(flet ($e58 (> ?e6 ?e13))
+(flet ($e59 (distinct v0 ?e12))
+(flet ($e60 (distinct ?e14 ?e9))
+(flet ($e61 (> ?e8 ?e15))
+(flet ($e62 (= ?e9 ?e16))
+(flet ($e63 (= ?e14 ?e13))
+(flet ($e64 (> ?e11 ?e6))
+(flet ($e65 (distinct ?e16 ?e9))
+(flet ($e66 (>= ?e5 ?e7))
+(flet ($e67 (<= ?e9 ?e17))
+(flet ($e68 (= ?e13 v0))
+(flet ($e69 (p0 ?e13))
+(let (?e70 (ite $e33 ?e18 ?e18))
+(let (?e71 (ite $e25 ?e21 ?e19))
+(let (?e72 (ite $e23 ?e71 ?e18))
+(let (?e73 (ite $e36 v1 ?e71))
+(let (?e74 (ite $e44 v1 ?e21))
+(let (?e75 (ite $e65 ?e20 ?e20))
+(let (?e76 (ite $e30 v1 ?e71))
+(let (?e77 (ite $e28 ?e21 ?e20))
+(let (?e78 (ite $e67 ?e77 ?e75))
+(let (?e79 (ite $e29 ?e21 ?e70))
+(let (?e80 (ite $e54 ?e18 ?e74))
+(let (?e81 (ite $e53 ?e80 ?e79))
+(let (?e82 (ite $e27 v1 ?e79))
+(let (?e83 (ite $e37 ?e18 ?e75))
+(let (?e84 (ite $e30 ?e78 ?e82))
+(let (?e85 (ite $e47 ?e74 ?e21))
+(let (?e86 (ite $e67 ?e19 ?e21))
+(let (?e87 (ite $e32 ?e78 ?e86))
+(let (?e88 (ite $e50 ?e72 ?e80))
+(let (?e89 (ite $e63 ?e84 ?e88))
+(let (?e90 (ite $e46 ?e73 ?e21))
+(let (?e91 (ite $e27 ?e20 ?e74))
+(let (?e92 (ite $e60 ?e91 ?e83))
+(let (?e93 (ite $e55 ?e71 ?e19))
+(let (?e94 (ite $e40 ?e85 ?e81))
+(let (?e95 (ite $e56 ?e78 ?e20))
+(let (?e96 (ite $e27 ?e92 ?e79))
+(let (?e97 (ite $e68 ?e95 ?e86))
+(let (?e98 (ite $e39 ?e77 ?e94))
+(let (?e99 (ite $e57 ?e87 ?e79))
+(let (?e100 (ite $e60 ?e91 ?e99))
+(let (?e101 (ite $e33 ?e89 ?e93))
+(let (?e102 (ite $e43 ?e72 ?e82))
+(let (?e103 (ite $e24 ?e74 ?e81))
+(let (?e104 (ite $e38 ?e99 ?e99))
+(let (?e105 (ite $e64 ?e91 ?e77))
+(let (?e106 (ite $e57 ?e93 ?e79))
+(let (?e107 (ite $e51 ?e96 ?e88))
+(let (?e108 (ite $e24 ?e76 ?e102))
+(let (?e109 (ite $e62 ?e93 ?e97))
+(let (?e110 (ite $e26 ?e106 v1))
+(let (?e111 (ite $e48 ?e106 ?e70))
+(let (?e112 (ite $e58 ?e73 ?e76))
+(let (?e113 (ite $e61 ?e111 ?e106))
+(let (?e114 (ite $e69 ?e105 ?e81))
+(let (?e115 (ite $e22 ?e96 ?e100))
+(let (?e116 (ite $e48 ?e109 ?e88))
+(let (?e117 (ite $e31 v1 ?e77))
+(let (?e118 (ite $e41 ?e93 ?e86))
+(let (?e119 (ite $e24 ?e113 ?e20))
+(let (?e120 (ite $e46 ?e101 ?e110))
+(let (?e121 (ite $e28 ?e77 ?e96))
+(let (?e122 (ite $e49 ?e107 ?e105))
+(let (?e123 (ite $e59 ?e21 ?e73))
+(let (?e124 (ite $e22 ?e116 ?e116))
+(let (?e125 (ite $e31 ?e77 ?e111))
+(let (?e126 (ite $e66 ?e103 ?e93))
+(let (?e127 (ite $e45 ?e96 ?e100))
+(let (?e128 (ite $e52 ?e125 ?e78))
+(let (?e129 (ite $e38 ?e70 ?e112))
+(let (?e130 (ite $e42 ?e105 ?e77))
+(let (?e131 (ite $e38 ?e91 ?e119))
+(let (?e132 (ite $e35 ?e113 ?e96))
+(let (?e133 (ite $e34 ?e115 ?e86))
+(let (?e134 (ite $e57 v0 ?e9))
+(let (?e135 (ite $e22 ?e7 ?e11))
+(let (?e136 (ite $e44 ?e135 ?e10))
+(let (?e137 (ite $e46 ?e10 ?e14))
+(let (?e138 (ite $e31 ?e4 ?e16))
+(let (?e139 (ite $e63 ?e17 ?e10))
+(let (?e140 (ite $e62 ?e4 ?e8))
+(let (?e141 (ite $e69 ?e12 ?e138))
+(let (?e142 (ite $e44 ?e13 ?e140))
+(let (?e143 (ite $e53 ?e15 ?e15))
+(let (?e144 (ite $e59 ?e142 ?e137))
+(let (?e145 (ite $e24 ?e4 ?e137))
+(let (?e146 (ite $e68 ?e13 ?e4))
+(let (?e147 (ite $e49 ?e12 ?e14))
+(let (?e148 (ite $e49 ?e6 ?e134))
+(let (?e149 (ite $e54 ?e137 ?e9))
+(let (?e150 (ite $e60 ?e5 ?e9))
+(let (?e151 (ite $e64 ?e13 ?e4))
+(let (?e152 (ite $e65 ?e139 ?e149))
+(let (?e153 (ite $e34 ?e143 ?e138))
+(let (?e154 (ite $e40 ?e145 ?e151))
+(let (?e155 (ite $e32 ?e141 ?e137))
+(let (?e156 (ite $e56 ?e16 ?e148))
+(let (?e157 (ite $e28 ?e152 ?e14))
+(let (?e158 (ite $e47 ?e141 ?e152))
+(let (?e159 (ite $e43 ?e8 ?e6))
+(let (?e160 (ite $e51 ?e135 ?e146))
+(let (?e161 (ite $e50 ?e141 ?e151))
+(let (?e162 (ite $e69 ?e14 ?e148))
+(let (?e163 (ite $e45 ?e145 ?e154))
+(let (?e164 (ite $e55 ?e150 ?e4))
+(let (?e165 (ite $e46 ?e146 ?e4))
+(let (?e166 (ite $e63 ?e142 ?e143))
+(let (?e167 (ite $e24 ?e156 ?e5))
+(let (?e168 (ite $e30 ?e164 ?e146))
+(let (?e169 (ite $e38 ?e11 ?e165))
+(let (?e170 (ite $e48 ?e12 ?e135))
+(let (?e171 (ite $e25 ?e168 ?e4))
+(let (?e172 (ite $e33 ?e163 ?e142))
+(let (?e173 (ite $e49 ?e7 ?e159))
+(let (?e174 (ite $e69 ?e16 ?e10))
+(let (?e175 (ite $e46 ?e156 ?e166))
+(let (?e176 (ite $e39 ?e135 ?e134))
+(let (?e177 (ite $e57 ?e161 ?e9))
+(let (?e178 (ite $e33 ?e153 ?e139))
+(let (?e179 (ite $e62 ?e138 ?e169))
+(let (?e180 (ite $e23 ?e146 ?e166))
+(let (?e181 (ite $e66 ?e140 ?e148))
+(let (?e182 (ite $e32 ?e163 ?e136))
+(let (?e183 (ite $e58 ?e134 ?e141))
+(let (?e184 (ite $e61 ?e9 ?e174))
+(let (?e185 (ite $e37 ?e155 ?e148))
+(let (?e186 (ite $e34 ?e157 ?e185))
+(let (?e187 (ite $e68 ?e139 ?e12))
+(let (?e188 (ite $e34 ?e164 ?e168))
+(let (?e189 (ite $e42 ?e160 ?e139))
+(let (?e190 (ite $e36 ?e17 ?e138))
+(let (?e191 (ite $e52 ?e173 ?e143))
+(let (?e192 (ite $e35 ?e157 ?e140))
+(let (?e193 (ite $e65 ?e139 ?e184))
+(let (?e194 (ite $e27 ?e9 ?e141))
+(let (?e195 (ite $e24 ?e167 ?e144))
+(let (?e196 (ite $e67 ?e177 ?e144))
+(let (?e197 (ite $e26 ?e14 ?e174))
+(let (?e198 (ite $e47 ?e182 ?e156))
+(let (?e199 (ite $e28 ?e156 ?e158))
+(let (?e200 (ite $e41 ?e163 ?e185))
+(let (?e201 (ite $e52 ?e190 ?e178))
+(let (?e202 (ite $e29 ?e186 ?e171))
+(let (?e203 (store ?e133 ?e177 ?e190))
+(let (?e204 (store ?e102 ?e193 ?e151))
+(let (?e205 (select ?e120 ?e173))
+(let (?e206 (store ?e101 ?e6 ?e202))
+(let (?e207 (f1 ?e114 ?e124 ?e87))
+(let (?e208 (f1 ?e99 ?e19 ?e116))
+(let (?e209 (f1 ?e91 ?e91 ?e91))
+(let (?e210 (f1 ?e92 ?e112 ?e95))
+(let (?e211 (f1 ?e210 ?e123 ?e72))
+(let (?e212 (f1 ?e82 ?e203 ?e84))
+(let (?e213 (f1 ?e127 ?e91 ?e122))
+(let (?e214 (f1 ?e75 ?e75 ?e75))
+(let (?e215 (f1 ?e126 ?e111 ?e209))
+(let (?e216 (f1 ?e77 ?e77 ?e77))
+(let (?e217 (f1 ?e94 ?e94 ?e94))
+(let (?e218 (f1 ?e80 ?e80 ?e87))
+(let (?e219 (f1 ?e80 ?e207 ?e73))
+(let (?e220 (f1 ?e76 ?e76 ?e90))
+(let (?e221 (f1 ?e128 ?e128 ?e207))
+(let (?e222 (f1 ?e86 ?e108 ?e98))
+(let (?e223 (f1 ?e109 ?e73 ?e72))
+(let (?e224 (f1 ?e97 ?e97 ?e80))
+(let (?e225 (f1 ?e223 ?e76 ?e206))
+(let (?e226 (f1 ?e113 ?e113 ?e113))
+(let (?e227 (f1 ?e86 ?e118 ?e204))
+(let (?e228 (f1 ?e116 ?e203 ?e214))
+(let (?e229 (f1 ?e88 ?e219 ?e120))
+(let (?e230 (f1 ?e70 ?e77 ?e220))
+(let (?e231 (f1 ?e109 ?e72 ?e91))
+(let (?e232 (f1 v1 ?e130 ?e211))
+(let (?e233 (f1 ?e91 ?e128 ?e130))
+(let (?e234 (f1 ?e21 ?e207 ?e117))
+(let (?e235 (f1 ?e78 ?e78 ?e133))
+(let (?e236 (f1 ?e115 ?e94 ?e210))
+(let (?e237 (f1 ?e100 ?e80 ?e214))
+(let (?e238 (f1 ?e113 ?e77 ?e120))
+(let (?e239 (f1 ?e113 ?e108 ?e212))
+(let (?e240 (f1 ?e107 ?e107 ?e226))
+(let (?e241 (f1 ?e106 ?e106 ?e235))
+(let (?e242 (f1 ?e121 ?e121 ?e219))
+(let (?e243 (f1 ?e110 ?e110 ?e110))
+(let (?e244 (f1 ?e115 ?e107 ?e225))
+(let (?e245 (f1 ?e226 ?e83 ?e100))
+(let (?e246 (f1 ?e18 ?e18 ?e116))
+(let (?e247 (f1 v1 ?e107 ?e98))
+(let (?e248 (f1 ?e235 ?e121 ?e241))
+(let (?e249 (f1 ?e71 ?e96 ?e210))
+(let (?e250 (f1 ?e101 ?e212 ?e237))
+(let (?e251 (f1 ?e132 ?e132 ?e110))
+(let (?e252 (f1 ?e133 ?e233 ?e129))
+(let (?e253 (f1 ?e77 ?e81 ?e118))
+(let (?e254 (f1 ?e231 ?e106 ?e98))
+(let (?e255 (f1 ?e87 ?e76 ?e73))
+(let (?e256 (f1 ?e248 ?e103 ?e222))
+(let (?e257 (f1 ?e105 ?e105 ?e254))
+(let (?e258 (f1 ?e243 ?e104 ?e120))
+(let (?e259 (f1 ?e20 ?e126 ?e243))
+(let (?e260 (f1 ?e259 ?e102 ?e115))
+(let (?e261 (f1 ?e128 ?e73 ?e222))
+(let (?e262 (f1 ?e125 ?e101 ?e126))
+(let (?e263 (f1 ?e119 ?e77 ?e240))
+(let (?e264 (f1 ?e131 ?e225 ?e229))
+(let (?e265 (f1 ?e254 ?e109 ?e230))
+(let (?e266 (f1 ?e211 ?e242 ?e219))
+(let (?e267 (f1 ?e85 ?e128 ?e76))
+(let (?e268 (f1 ?e89 ?e241 ?e262))
+(let (?e269 (f1 ?e74 ?e122 ?e117))
+(let (?e270 (f1 ?e93 ?e93 ?e93))
+(let (?e271 (f1 ?e79 ?e79 ?e79))
+(let (?e272 (* ?e192 (~ ?e2)))
+(let (?e273 (ite (p0 ?e177) 1 0))
+(let (?e274 (ite (p0 ?e165) 1 0))
+(let (?e275 (~ ?e156))
+(let (?e276 (+ ?e162 ?e12))
+(let (?e277 (f0 ?e148 ?e272))
+(let (?e278 (f0 ?e8 ?e11))
+(let (?e279 (+ ?e198 ?e6))
+(let (?e280 (~ ?e182))
+(let (?e281 (+ ?e16 ?e141))
+(let (?e282 (* (~ ?e3) ?e157))
+(let (?e283 (ite (p0 ?e146) 1 0))
+(let (?e284 (~ ?e189))
+(let (?e285 (- ?e277 ?e189))
+(let (?e286 (- ?e284 ?e158))
+(let (?e287 (~ ?e176))
+(let (?e288 (* ?e3 ?e178))
+(let (?e289 (* ?e3 ?e136))
+(let (?e290 (* ?e3 ?e4))
+(let (?e291 (- ?e146 ?e152))
+(let (?e292 (f0 ?e135 ?e136))
+(let (?e293 (f0 ?e278 ?e161))
+(let (?e294 (~ ?e10))
+(let (?e295 (ite (p0 ?e163) 1 0))
+(let (?e296 (f0 ?e8 ?e192))
+(let (?e297 (* ?e159 (~ ?e3)))
+(let (?e298 (- ?e145 ?e159))
+(let (?e299 (- ?e158 ?e200))
+(let (?e300 (+ ?e170 ?e7))
+(let (?e301 (f0 ?e142 ?e295))
+(let (?e302 (+ ?e193 ?e149))
+(let (?e303 (* ?e301 (~ ?e3)))
+(let (?e304 (* ?e190 ?e2))
+(let (?e305 (- ?e15 ?e152))
+(let (?e306 (+ ?e179 ?e138))
+(let (?e307 (* (~ ?e3) ?e147))
+(let (?e308 (- ?e178 ?e202))
+(let (?e309 (* ?e172 ?e2))
+(let (?e310 (ite (p0 ?e183) 1 0))
+(let (?e311 (f0 ?e294 ?e149))
+(let (?e312 (- ?e151 ?e202))
+(let (?e313 (f0 ?e164 v0))
+(let (?e314 (f0 ?e165 ?e4))
+(let (?e315 (- ?e143 ?e285))
+(let (?e316 (f0 ?e134 ?e174))
+(let (?e317 (~ ?e175))
+(let (?e318 (+ ?e9 ?e185))
+(let (?e319 (* (~ ?e2) ?e137))
+(let (?e320 (* ?e169 ?e2))
+(let (?e321 (* ?e3 ?e146))
+(let (?e322 (* ?e184 ?e2))
+(let (?e323 (f0 ?e179 ?e169))
+(let (?e324 (f0 ?e144 ?e297))
+(let (?e325 (+ ?e153 ?e154))
+(let (?e326 (f0 ?e173 ?e151))
+(let (?e327 (~ ?e191))
+(let (?e328 (f0 ?e201 ?e323))
+(let (?e329 (+ ?e278 ?e272))
+(let (?e330 (* ?e150 (~ ?e2)))
+(let (?e331 (* ?e197 (~ ?e3)))
+(let (?e332 (- ?e205 ?e169))
+(let (?e333 (- ?e17 ?e288))
+(let (?e334 (ite (p0 ?e199) 1 0))
+(let (?e335 (f0 ?e181 ?e304))
+(let (?e336 (- ?e14 ?e201))
+(let (?e337 (f0 ?e168 ?e291))
+(let (?e338 (f0 ?e279 ?e180))
+(let (?e339 (+ ?e160 ?e162))
+(let (?e340 (- ?e196 ?e163))
+(let (?e341 (f0 ?e140 ?e175))
+(let (?e342 (- ?e147 ?e282))
+(let (?e343 (* ?e5 (~ ?e3)))
+(let (?e344 (f0 ?e284 ?e298))
+(let (?e345 (- ?e284 ?e272))
+(let (?e346 (* ?e2 ?e326))
+(let (?e347 (ite (p0 ?e139) 1 0))
+(let (?e348 (f0 ?e273 ?e285))
+(let (?e349 (* ?e2 ?e315))
+(let (?e350 (* (~ ?e3) ?e15))
+(let (?e351 (ite (p0 ?e320) 1 0))
+(let (?e352 (- ?e155 ?e317))
+(let (?e353 (* ?e194 ?e3))
+(let (?e354 (~ ?e143))
+(let (?e355 (ite (p0 ?e338) 1 0))
+(let (?e356 (- ?e158 ?e151))
+(let (?e357 (ite (p0 ?e296) 1 0))
+(let (?e358 (- ?e166 ?e9))
+(let (?e359 (~ ?e195))
+(let (?e360 (+ ?e148 ?e200))
+(let (?e361 (- ?e186 ?e162))
+(let (?e362 (- ?e192 ?e136))
+(let (?e363 (- ?e167 ?e301))
+(let (?e364 (ite (p0 ?e13) 1 0))
+(let (?e365 (ite (p0 ?e282) 1 0))
+(let (?e366 (* (~ ?e3) ?e8))
+(let (?e367 (- ?e342 ?e360))
+(let (?e368 (- ?e181 ?e4))
+(let (?e369 (* ?e3 ?e188))
+(let (?e370 (- ?e171 ?e146))
+(let (?e371 (* ?e293 (~ ?e2)))
+(let (?e372 (* (~ ?e2) ?e187))
+(flet ($e373 (p1 ?e101))
+(flet ($e374 (p1 ?e247))
+(flet ($e375 (p1 ?e270))
+(flet ($e376 (p1 ?e125))
+(flet ($e377 (p1 ?e235))
+(flet ($e378 (p1 ?e254))
+(flet ($e379 (p1 ?e214))
+(flet ($e380 (p1 ?e111))
+(flet ($e381 (p1 ?e112))
+(flet ($e382 (p1 ?e239))
+(flet ($e383 (p1 ?e110))
+(flet ($e384 (p1 ?e212))
+(flet ($e385 (p1 ?e75))
+(flet ($e386 (p1 ?e261))
+(flet ($e387 (p1 ?e258))
+(flet ($e388 (p1 ?e223))
+(flet ($e389 (p1 ?e124))
+(flet ($e390 (p1 ?e209))
+(flet ($e391 (p1 ?e120))
+(flet ($e392 (p1 ?e89))
+(flet ($e393 (p1 ?e207))
+(flet ($e394 (p1 ?e90))
+(flet ($e395 (p1 ?e81))
+(flet ($e396 (p1 ?e204))
+(flet ($e397 (p1 ?e94))
+(flet ($e398 (p1 ?e125))
+(flet ($e399 (p1 ?e230))
+(flet ($e400 (p1 ?e132))
+(flet ($e401 (p1 ?e93))
+(flet ($e402 (p1 ?e266))
+(flet ($e403 (p1 ?e79))
+(flet ($e404 (p1 ?e92))
+(flet ($e405 (p1 ?e241))
+(flet ($e406 (p1 ?e70))
+(flet ($e407 (p1 ?e95))
+(flet ($e408 (p1 ?e250))
+(flet ($e409 (p1 ?e110))
+(flet ($e410 (p1 ?e267))
+(flet ($e411 (p1 ?e234))
+(flet ($e412 (p1 ?e248))
+(flet ($e413 (p1 ?e98))
+(flet ($e414 (p1 ?e133))
+(flet ($e415 (p1 ?e128))
+(flet ($e416 (p1 ?e84))
+(flet ($e417 (p1 ?e83))
+(flet ($e418 (p1 ?e77))
+(flet ($e419 (p1 ?e251))
+(flet ($e420 (p1 ?e21))
+(flet ($e421 (p1 ?e263))
+(flet ($e422 (p1 ?e114))
+(flet ($e423 (p1 ?e19))
+(flet ($e424 (p1 ?e229))
+(flet ($e425 (p1 ?e242))
+(flet ($e426 (p1 ?e209))
+(flet ($e427 (p1 ?e221))
+(flet ($e428 (p1 ?e78))
+(flet ($e429 (p1 ?e70))
+(flet ($e430 (p1 ?e264))
+(flet ($e431 (p1 ?e224))
+(flet ($e432 (p1 ?e20))
+(flet ($e433 (p1 ?e246))
+(flet ($e434 (p1 ?e90))
+(flet ($e435 (p1 ?e90))
+(flet ($e436 (p1 ?e129))
+(flet ($e437 (p1 ?e129))
+(flet ($e438 (p1 ?e247))
+(flet ($e439 (p1 ?e252))
+(flet ($e440 (p1 ?e255))
+(flet ($e441 (p1 ?e106))
+(flet ($e442 (p1 ?e228))
+(flet ($e443 (p1 ?e242))
+(flet ($e444 (p1 ?e108))
+(flet ($e445 (p1 ?e86))
+(flet ($e446 (p1 ?e88))
+(flet ($e447 (p1 ?e238))
+(flet ($e448 (p1 ?e233))
+(flet ($e449 (p1 ?e241))
+(flet ($e450 (p1 ?e255))
+(flet ($e451 (p1 ?e74))
+(flet ($e452 (p1 ?e95))
+(flet ($e453 (p1 ?e103))
+(flet ($e454 (p1 ?e130))
+(flet ($e455 (p1 ?e269))
+(flet ($e456 (p1 ?e240))
+(flet ($e457 (p1 ?e117))
+(flet ($e458 (p1 ?e241))
+(flet ($e459 (p1 ?e127))
+(flet ($e460 (p1 ?e232))
+(flet ($e461 (p1 ?e73))
+(flet ($e462 (p1 ?e253))
+(flet ($e463 (p1 ?e268))
+(flet ($e464 (p1 ?e133))
+(flet ($e465 (p1 ?e101))
+(flet ($e466 (p1 ?e216))
+(flet ($e467 (p1 ?e72))
+(flet ($e468 (p1 ?e118))
+(flet ($e469 (p1 ?e109))
+(flet ($e470 (p1 ?e123))
+(flet ($e471 (p1 ?e71))
+(flet ($e472 (p1 ?e103))
+(flet ($e473 (p1 ?e111))
+(flet ($e474 (p1 ?e215))
+(flet ($e475 (p1 ?e102))
+(flet ($e476 (p1 ?e260))
+(flet ($e477 (p1 ?e107))
+(flet ($e478 (p1 ?e244))
+(flet ($e479 (p1 ?e87))
+(flet ($e480 (p1 ?e18))
+(flet ($e481 (p1 ?e88))
+(flet ($e482 (p1 ?e208))
+(flet ($e483 (p1 ?e84))
+(flet ($e484 (p1 ?e217))
+(flet ($e485 (p1 ?e233))
+(flet ($e486 (p1 ?e265))
+(flet ($e487 (p1 ?e100))
+(flet ($e488 (p1 ?e210))
+(flet ($e489 (p1 ?e242))
+(flet ($e490 (p1 ?e214))
+(flet ($e491 (p1 ?e230))
+(flet ($e492 (p1 ?e116))
+(flet ($e493 (p1 ?e104))
+(flet ($e494 (p1 ?e80))
+(flet ($e495 (p1 ?e203))
+(flet ($e496 (p1 ?e76))
+(flet ($e497 (p1 ?e271))
+(flet ($e498 (p1 v1))
+(flet ($e499 (p1 ?e106))
+(flet ($e500 (p1 ?e204))
+(flet ($e501 (p1 ?e113))
+(flet ($e502 (p1 ?e262))
+(flet ($e503 (p1 ?e105))
+(flet ($e504 (p1 ?e225))
+(flet ($e505 (p1 ?e131))
+(flet ($e506 (p1 ?e121))
+(flet ($e507 (p1 ?e119))
+(flet ($e508 (p1 ?e248))
+(flet ($e509 (p1 ?e219))
+(flet ($e510 (p1 ?e71))
+(flet ($e511 (p1 ?e96))
+(flet ($e512 (p1 ?e74))
+(flet ($e513 (p1 ?e270))
+(flet ($e514 (p1 ?e211))
+(flet ($e515 (p1 ?e236))
+(flet ($e516 (p1 ?e82))
+(flet ($e517 (p1 ?e229))
+(flet ($e518 (p1 ?e85))
+(flet ($e519 (p1 ?e122))
+(flet ($e520 (p1 ?e243))
+(flet ($e521 (p1 ?e97))
+(flet ($e522 (p1 ?e96))
+(flet ($e523 (p1 ?e231))
+(flet ($e524 (p1 ?e234))
+(flet ($e525 (p1 ?e112))
+(flet ($e526 (p1 ?e259))
+(flet ($e527 (p1 ?e213))
+(flet ($e528 (p1 v1))
+(flet ($e529 (p1 ?e206))
+(flet ($e530 (p1 ?e222))
+(flet ($e531 (p1 ?e249))
+(flet ($e532 (p1 ?e218))
+(flet ($e533 (p1 ?e256))
+(flet ($e534 (p1 ?e220))
+(flet ($e535 (p1 ?e264))
+(flet ($e536 (p1 ?e246))
+(flet ($e537 (p1 ?e94))
+(flet ($e538 (p1 ?e125))
+(flet ($e539 (p1 ?e18))
+(flet ($e540 (p1 ?e119))
+(flet ($e541 (p1 ?e127))
+(flet ($e542 (p1 ?e99))
+(flet ($e543 (p1 ?e126))
+(flet ($e544 (p1 ?e263))
+(flet ($e545 (p1 ?e78))
+(flet ($e546 (p1 ?e257))
+(flet ($e547 (p1 ?e81))
+(flet ($e548 (p1 ?e76))
+(flet ($e549 (p1 ?e115))
+(flet ($e550 (p1 ?e96))
+(flet ($e551 (p1 ?e99))
+(flet ($e552 (p1 ?e265))
+(flet ($e553 (p1 ?e237))
+(flet ($e554 (p1 ?e226))
+(flet ($e555 (p1 ?e244))
+(flet ($e556 (p1 ?e91))
+(flet ($e557 (p1 ?e245))
+(flet ($e558 (p1 ?e72))
+(flet ($e559 (p1 ?e130))
+(flet ($e560 (p1 ?e219))
+(flet ($e561 (p1 ?e227))
+(flet ($e562 (p0 ?e8))
+(flet ($e563 (>= ?e162 ?e164))
+(flet ($e564 (>= ?e346 ?e289))
+(flet ($e565 (< ?e317 ?e287))
+(flet ($e566 (<= ?e16 ?e363))
+(flet ($e567 (distinct ?e357 ?e317))
+(flet ($e568 (>= ?e294 ?e141))
+(flet ($e569 (> ?e358 ?e10))
+(flet ($e570 (= ?e12 ?e328))
+(flet ($e571 (> ?e301 ?e307))
+(flet ($e572 (< ?e280 ?e321))
+(flet ($e573 (p0 ?e153))
+(flet ($e574 (< ?e137 ?e315))
+(flet ($e575 (distinct ?e370 ?e200))
+(flet ($e576 (> ?e350 ?e202))
+(flet ($e577 (> ?e165 ?e298))
+(flet ($e578 (distinct ?e178 ?e282))
+(flet ($e579 (<= ?e201 ?e338))
+(flet ($e580 (distinct ?e324 ?e158))
+(flet ($e581 (= ?e9 ?e14))
+(flet ($e582 (>= ?e281 ?e359))
+(flet ($e583 (< ?e329 ?e175))
+(flet ($e584 (< ?e311 ?e325))
+(flet ($e585 (>= ?e188 ?e146))
+(flet ($e586 (= ?e174 ?e17))
+(flet ($e587 (distinct ?e277 ?e279))
+(flet ($e588 (< ?e294 ?e295))
+(flet ($e589 (= ?e361 ?e369))
+(flet ($e590 (<= ?e347 ?e277))
+(flet ($e591 (<= ?e277 ?e163))
+(flet ($e592 (> ?e157 ?e332))
+(flet ($e593 (>= ?e320 ?e320))
+(flet ($e594 (distinct ?e364 ?e332))
+(flet ($e595 (<= ?e349 ?e184))
+(flet ($e596 (distinct ?e284 ?e195))
+(flet ($e597 (> ?e301 ?e335))
+(flet ($e598 (<= ?e205 ?e156))
+(flet ($e599 (<= ?e136 ?e345))
+(flet ($e600 (<= ?e354 ?e357))
+(flet ($e601 (< ?e339 ?e282))
+(flet ($e602 (< ?e341 ?e135))
+(flet ($e603 (< ?e7 ?e289))
+(flet ($e604 (p0 ?e364))
+(flet ($e605 (p0 ?e187))
+(flet ($e606 (distinct ?e149 ?e319))
+(flet ($e607 (p0 ?e297))
+(flet ($e608 (= ?e151 ?e9))
+(flet ($e609 (< ?e367 ?e148))
+(flet ($e610 (= ?e287 ?e13))
+(flet ($e611 (= ?e168 ?e278))
+(flet ($e612 (< ?e345 ?e290))
+(flet ($e613 (p0 ?e196))
+(flet ($e614 (p0 ?e313))
+(flet ($e615 (<= ?e305 ?e149))
+(flet ($e616 (>= ?e372 ?e330))
+(flet ($e617 (distinct ?e366 ?e341))
+(flet ($e618 (= ?e344 ?e329))
+(flet ($e619 (<= ?e145 ?e310))
+(flet ($e620 (> ?e140 ?e367))
+(flet ($e621 (> ?e191 ?e196))
+(flet ($e622 (> ?e323 ?e326))
+(flet ($e623 (< ?e181 ?e190))
+(flet ($e624 (< ?e273 ?e139))
+(flet ($e625 (= ?e316 ?e361))
+(flet ($e626 (> ?e346 ?e154))
+(flet ($e627 (< ?e332 ?e304))
+(flet ($e628 (p0 ?e300))
+(flet ($e629 (<= ?e302 ?e359))
+(flet ($e630 (<= ?e357 ?e341))
+(flet ($e631 (p0 ?e337))
+(flet ($e632 (>= ?e318 ?e143))
+(flet ($e633 (= ?e173 ?e338))
+(flet ($e634 (= ?e11 ?e359))
+(flet ($e635 (<= ?e276 ?e10))
+(flet ($e636 (<= ?e333 ?e290))
+(flet ($e637 (<= ?e286 ?e293))
+(flet ($e638 (< ?e150 ?e173))
+(flet ($e639 (distinct ?e306 ?e153))
+(flet ($e640 (>= ?e272 ?e176))
+(flet ($e641 (distinct ?e343 ?e346))
+(flet ($e642 (distinct ?e371 ?e283))
+(flet ($e643 (distinct v0 ?e365))
+(flet ($e644 (= ?e312 ?e317))
+(flet ($e645 (<= ?e134 ?e151))
+(flet ($e646 (> ?e322 ?e189))
+(flet ($e647 (p0 ?e356))
+(flet ($e648 (>= ?e166 ?e341))
+(flet ($e649 (< ?e342 ?e313))
+(flet ($e650 (p0 ?e336))
+(flet ($e651 (= ?e187 ?e10))
+(flet ($e652 (distinct ?e362 ?e195))
+(flet ($e653 (>= ?e167 ?e305))
+(flet ($e654 (< ?e170 ?e288))
+(flet ($e655 (distinct ?e161 ?e166))
+(flet ($e656 (< ?e299 ?e283))
+(flet ($e657 (p0 ?e327))
+(flet ($e658 (= ?e340 ?e9))
+(flet ($e659 (p0 ?e340))
+(flet ($e660 (<= ?e177 ?e330))
+(flet ($e661 (distinct ?e205 ?e12))
+(flet ($e662 (distinct ?e339 ?e8))
+(flet ($e663 (= ?e330 ?e311))
+(flet ($e664 (p0 ?e171))
+(flet ($e665 (= ?e5 ?e161))
+(flet ($e666 (< ?e136 ?e277))
+(flet ($e667 (p0 ?e15))
+(flet ($e668 (p0 ?e168))
+(flet ($e669 (= ?e334 ?e328))
+(flet ($e670 (p0 ?e367))
+(flet ($e671 (<= ?e342 ?e6))
+(flet ($e672 (distinct ?e306 ?e14))
+(flet ($e673 (<= ?e274 ?e320))
+(flet ($e674 (> ?e171 ?e173))
+(flet ($e675 (distinct ?e365 ?e5))
+(flet ($e676 (distinct ?e327 ?e351))
+(flet ($e677 (distinct ?e16 ?e277))
+(flet ($e678 (= ?e361 ?e371))
+(flet ($e679 (>= ?e179 ?e319))
+(flet ($e680 (>= ?e188 ?e303))
+(flet ($e681 (p0 ?e161))
+(flet ($e682 (> ?e353 ?e354))
+(flet ($e683 (> ?e142 ?e337))
+(flet ($e684 (< ?e159 ?e281))
+(flet ($e685 (>= ?e306 ?e183))
+(flet ($e686 (>= ?e198 ?e143))
+(flet ($e687 (= ?e285 ?e194))
+(flet ($e688 (= ?e138 ?e273))
+(flet ($e689 (<= ?e172 ?e290))
+(flet ($e690 (< ?e16 ?e12))
+(flet ($e691 (= ?e368 ?e287))
+(flet ($e692 (>= ?e340 ?e308))
+(flet ($e693 (= ?e194 ?e370))
+(flet ($e694 (distinct ?e296 ?e198))
+(flet ($e695 (= ?e4 ?e139))
+(flet ($e696 (> ?e275 ?e296))
+(flet ($e697 (p0 ?e352))
+(flet ($e698 (= ?e205 ?e138))
+(flet ($e699 (>= ?e331 ?e308))
+(flet ($e700 (>= ?e147 ?e287))
+(flet ($e701 (p0 ?e306))
+(flet ($e702 (> ?e348 ?e344))
+(flet ($e703 (>= ?e169 ?e353))
+(flet ($e704 (<= ?e180 ?e337))
+(flet ($e705 (< ?e287 ?e301))
+(flet ($e706 (> ?e360 ?e309))
+(flet ($e707 (distinct ?e184 ?e17))
+(flet ($e708 (>= ?e173 ?e153))
+(flet ($e709 (> ?e339 ?e14))
+(flet ($e710 (> ?e370 ?e327))
+(flet ($e711 (distinct ?e368 ?e301))
+(flet ($e712 (< ?e160 ?e279))
+(flet ($e713 (distinct ?e163 ?e5))
+(flet ($e714 (>= ?e356 ?e156))
+(flet ($e715 (< ?e192 ?e176))
+(flet ($e716 (distinct ?e302 ?e140))
+(flet ($e717 (> ?e300 ?e355))
+(flet ($e718 (<= ?e291 ?e324))
+(flet ($e719 (p0 ?e314))
+(flet ($e720 (>= ?e199 ?e369))
+(flet ($e721 (= ?e274 ?e364))
+(flet ($e722 (p0 ?e205))
+(flet ($e723 (distinct ?e317 ?e10))
+(flet ($e724 (> ?e155 ?e169))
+(flet ($e725 (>= ?e182 ?e280))
+(flet ($e726 (>= ?e292 ?e331))
+(flet ($e727 (p0 ?e193))
+(flet ($e728 (< ?e190 ?e366))
+(flet ($e729 (<= ?e179 ?e324))
+(flet ($e730 (> ?e289 ?e4))
+(flet ($e731 (>= ?e186 ?e283))
+(flet ($e732 (<= ?e185 ?e339))
+(flet ($e733 (<= ?e308 ?e365))
+(flet ($e734 (> ?e317 ?e367))
+(flet ($e735 (p0 v0))
+(flet ($e736 (>= ?e300 ?e288))
+(flet ($e737 (>= ?e317 ?e192))
+(flet ($e738 (distinct ?e187 ?e190))
+(flet ($e739 (> ?e272 ?e189))
+(flet ($e740 (> ?e152 ?e159))
+(flet ($e741 (<= ?e274 ?e179))
+(flet ($e742 (< ?e304 ?e281))
+(flet ($e743 (p0 ?e135))
+(flet ($e744 (>= ?e366 ?e156))
+(flet ($e745 (<= ?e197 ?e338))
+(flet ($e746 (distinct ?e349 ?e339))
+(flet ($e747 (distinct ?e284 ?e167))
+(flet ($e748 (= ?e144 ?e134))
+(flet ($e749 (not $e411))
+(flet ($e750 (xor $e519 $e498))
+(flet ($e751 (implies $e639 $e39))
+(flet ($e752 (or $e60 $e590))
+(flet ($e753 (or $e644 $e62))
+(flet ($e754 (or $e447 $e683))
+(flet ($e755 (if_then_else $e712 $e387 $e26))
+(flet ($e756 (implies $e727 $e661))
+(flet ($e757 (if_then_else $e653 $e749 $e31))
+(flet ($e758 (implies $e757 $e607))
+(flet ($e759 (not $e591))
+(flet ($e760 (or $e725 $e677))
+(flet ($e761 (xor $e614 $e461))
+(flet ($e762 (and $e500 $e713))
+(flet ($e763 (iff $e584 $e656))
+(flet ($e764 (implies $e422 $e487))
+(flet ($e765 (if_then_else $e420 $e423 $e692))
+(flet ($e766 (xor $e27 $e480))
+(flet ($e767 (or $e602 $e43))
+(flet ($e768 (or $e723 $e453))
+(flet ($e769 (not $e389))
+(flet ($e770 (and $e600 $e391))
+(flet ($e771 (and $e493 $e706))
+(flet ($e772 (implies $e716 $e655))
+(flet ($e773 (not $e633))
+(flet ($e774 (iff $e528 $e22))
+(flet ($e775 (if_then_else $e431 $e474 $e507))
+(flet ($e776 (implies $e437 $e388))
+(flet ($e777 (if_then_else $e45 $e593 $e440))
+(flet ($e778 (implies $e703 $e549))
+(flet ($e779 (xor $e581 $e574))
+(flet ($e780 (xor $e401 $e38))
+(flet ($e781 (not $e646))
+(flet ($e782 (iff $e376 $e729))
+(flet ($e783 (if_then_else $e777 $e451 $e696))
+(flet ($e784 (and $e565 $e627))
+(flet ($e785 (implies $e415 $e617))
+(flet ($e786 (if_then_else $e746 $e785 $e408))
+(flet ($e787 (or $e648 $e414))
+(flet ($e788 (and $e527 $e473))
+(flet ($e789 (xor $e66 $e709))
+(flet ($e790 (and $e564 $e479))
+(flet ($e791 (xor $e448 $e520))
+(flet ($e792 (if_then_else $e702 $e385 $e413))
+(flet ($e793 (or $e611 $e46))
+(flet ($e794 (implies $e485 $e418))
+(flet ($e795 (and $e542 $e396))
+(flet ($e796 (or $e454 $e740))
+(flet ($e797 (iff $e782 $e640))
+(flet ($e798 (xor $e658 $e637))
+(flet ($e799 (and $e753 $e626))
+(flet ($e800 (or $e442 $e523))
+(flet ($e801 (implies $e642 $e776))
+(flet ($e802 (implies $e625 $e524))
+(flet ($e803 (if_then_else $e559 $e596 $e790))
+(flet ($e804 (xor $e750 $e50))
+(flet ($e805 (not $e463))
+(flet ($e806 (not $e651))
+(flet ($e807 (or $e419 $e674))
+(flet ($e808 (implies $e622 $e435))
+(flet ($e809 (if_then_else $e700 $e405 $e689))
+(flet ($e810 (iff $e583 $e34))
+(flet ($e811 (iff $e561 $e707))
+(flet ($e812 (implies $e562 $e735))
+(flet ($e813 (not $e58))
+(flet ($e814 (iff $e481 $e615))
+(flet ($e815 (not $e450))
+(flet ($e816 (and $e813 $e638))
+(flet ($e817 (and $e695 $e536))
+(flet ($e818 (and $e477 $e569))
+(flet ($e819 (iff $e784 $e478))
+(flet ($e820 (not $e384))
+(flet ($e821 (implies $e510 $e508))
+(flet ($e822 (iff $e526 $e56))
+(flet ($e823 (not $e634))
+(flet ($e824 (iff $e531 $e538))
+(flet ($e825 (or $e787 $e445))
+(flet ($e826 (iff $e63 $e578))
+(flet ($e827 (and $e496 $e618))
+(flet ($e828 (or $e662 $e613))
+(flet ($e829 (iff $e601 $e25))
+(flet ($e830 (not $e691))
+(flet ($e831 (not $e530))
+(flet ($e832 (and $e654 $e570))
+(flet ($e833 (or $e754 $e802))
+(flet ($e834 (and $e551 $e717))
+(flet ($e835 (xor $e53 $e586))
+(flet ($e836 (implies $e763 $e64))
+(flet ($e837 (iff $e760 $e766))
+(flet ($e838 (if_then_else $e805 $e444 $e395))
+(flet ($e839 (xor $e718 $e816))
+(flet ($e840 (if_then_else $e592 $e57 $e681))
+(flet ($e841 (iff $e379 $e488))
+(flet ($e842 (iff $e775 $e428))
+(flet ($e843 (not $e636))
+(flet ($e844 (and $e623 $e624))
+(flet ($e845 (xor $e409 $e705))
+(flet ($e846 (and $e489 $e557))
+(flet ($e847 (if_then_else $e41 $e460 $e724))
+(flet ($e848 (implies $e779 $e834))
+(flet ($e849 (implies $e769 $e739))
+(flet ($e850 (implies $e686 $e759))
+(flet ($e851 (if_then_else $e483 $e789 $e719))
+(flet ($e852 (not $e641))
+(flet ($e853 (implies $e567 $e803))
+(flet ($e854 (if_then_else $e742 $e378 $e843))
+(flet ($e855 (iff $e434 $e398))
+(flet ($e856 (or $e827 $e400))
+(flet ($e857 (xor $e563 $e687))
+(flet ($e858 (implies $e33 $e744))
+(flet ($e859 (implies $e793 $e455))
+(flet ($e860 (iff $e539 $e823))
+(flet ($e861 (or $e61 $e443))
+(flet ($e862 (and $e425 $e629))
+(flet ($e863 (not $e585))
+(flet ($e864 (not $e664))
+(flet ($e865 (and $e678 $e669))
+(flet ($e866 (or $e30 $e667))
+(flet ($e867 (or $e647 $e861))
+(flet ($e868 (xor $e35 $e492))
+(flet ($e869 (or $e577 $e685))
+(flet ($e870 (if_then_else $e393 $e51 $e69))
+(flet ($e871 (or $e711 $e589))
+(flet ($e872 (or $e466 $e863))
+(flet ($e873 (and $e44 $e858))
+(flet ($e874 (implies $e786 $e798))
+(flet ($e875 (implies $e558 $e844))
+(flet ($e876 (or $e441 $e649))
+(flet ($e877 (implies $e36 $e518))
+(flet ($e878 (xor $e751 $e675))
+(flet ($e879 (xor $e575 $e682))
+(flet ($e880 (iff $e821 $e801))
+(flet ($e881 (not $e791))
+(flet ($e882 (not $e394))
+(flet ($e883 (and $e630 $e459))
+(flet ($e884 (iff $e877 $e40))
+(flet ($e885 (if_then_else $e495 $e399 $e374))
+(flet ($e886 (or $e869 $e29))
+(flet ($e887 (iff $e486 $e845))
+(flet ($e888 (iff $e738 $e603))
+(flet ($e889 (xor $e521 $e566))
+(flet ($e890 (xor $e604 $e814))
+(flet ($e891 (if_then_else $e694 $e541 $e535))
+(flet ($e892 (and $e554 $e732))
+(flet ($e893 (implies $e880 $e822))
+(flet ($e894 (implies $e668 $e870))
+(flet ($e895 (if_then_else $e795 $e672 $e470))
+(flet ($e896 (implies $e806 $e560))
+(flet ($e897 (implies $e893 $e841))
+(flet ($e898 (if_then_else $e812 $e835 $e887))
+(flet ($e899 (or $e842 $e576))
+(flet ($e900 (not $e676))
+(flet ($e901 (or $e878 $e768))
+(flet ($e902 (and $e726 $e889))
+(flet ($e903 (not $e587))
+(flet ($e904 (and $e375 $e652))
+(flet ($e905 (implies $e874 $e761))
+(flet ($e906 (not $e469))
+(flet ($e907 (xor $e728 $e888))
+(flet ($e908 (if_then_else $e547 $e458 $e905))
+(flet ($e909 (not $e848))
+(flet ($e910 (xor $e810 $e799))
+(flet ($e911 (not $e553))
+(flet ($e912 (if_then_else $e612 $e772 $e433))
+(flet ($e913 (and $e745 $e872))
+(flet ($e914 (xor $e688 $e882))
+(flet ($e915 (xor $e421 $e780))
+(flet ($e916 (implies $e714 $e693))
+(flet ($e917 (implies $e424 $e467))
+(flet ($e918 (or $e770 $e482))
+(flet ($e919 (if_then_else $e765 $e839 $e608))
+(flet ($e920 (implies $e494 $e430))
+(flet ($e921 (and $e620 $e873))
+(flet ($e922 (if_then_else $e901 $e833 $e511))
+(flet ($e923 (and $e643 $e800))
+(flet ($e924 (xor $e912 $e820))
+(flet ($e925 (iff $e49 $e23))
+(flet ($e926 (iff $e830 $e914))
+(flet ($e927 (xor $e919 $e32))
+(flet ($e928 (implies $e859 $e853))
+(flet ($e929 (or $e771 $e406))
+(flet ($e930 (and $e824 $e514))
+(flet ($e931 (if_then_else $e509 $e548 $e851))
+(flet ($e932 (or $e865 $e606))
+(flet ($e933 (not $e47))
+(flet ($e934 (if_then_else $e571 $e894 $e657))
+(flet ($e935 (implies $e891 $e758))
+(flet ($e936 (or $e502 $e532))
+(flet ($e937 (and $e619 $e831))
+(flet ($e938 (or $e529 $e794))
+(flet ($e939 (and $e819 $e807))
+(flet ($e940 (if_then_else $e383 $e24 $e896))
+(flet ($e941 (iff $e934 $e934))
+(flet ($e942 (implies $e417 $e402))
+(flet ($e943 (implies $e426 $e412))
+(flet ($e944 (not $e849))
+(flet ($e945 (or $e941 $e499))
+(flet ($e946 (if_then_else $e631 $e895 $e663))
+(flet ($e947 (iff $e928 $e403))
+(flet ($e948 (and $e826 $e730))
+(flet ($e949 (not $e397))
+(flet ($e950 (implies $e390 $e710))
+(flet ($e951 (iff $e932 $e920))
+(flet ($e952 (not $e52))
+(flet ($e953 (or $e862 $e28))
+(flet ($e954 (if_then_else $e597 $e599 $e762))
+(flet ($e955 (implies $e54 $e946))
+(flet ($e956 (or $e513 $e755))
+(flet ($e957 (if_then_else $e505 $e955 $e809))
+(flet ($e958 (if_then_else $e884 $e792 $e927))
+(flet ($e959 (and $e540 $e438))
+(flet ($e960 (or $e909 $e462))
+(flet ($e961 (and $e491 $e860))
+(flet ($e962 (xor $e943 $e788))
+(flet ($e963 (xor $e736 $e55))
+(flet ($e964 (iff $e825 $e864))
+(flet ($e965 (if_then_else $e933 $e846 $e582))
+(flet ($e966 (implies $e836 $e452))
+(flet ($e967 (implies $e796 $e811))
+(flet ($e968 (and $e867 $e818))
+(flet ($e969 (iff $e944 $e621))
+(flet ($e970 (or $e650 $e721))
+(flet ($e971 (if_then_else $e381 $e690 $e773))
+(flet ($e972 (implies $e947 $e950))
+(flet ($e973 (and $e948 $e898))
+(flet ($e974 (implies $e840 $e490))
+(flet ($e975 (if_then_else $e537 $e465 $e949))
+(flet ($e976 (and $e924 $e446))
+(flet ($e977 (and $e572 $e525))
+(flet ($e978 (xor $e817 $e464))
+(flet ($e979 (implies $e883 $e722))
+(flet ($e980 (implies $e545 $e767))
+(flet ($e981 (and $e48 $e966))
+(flet ($e982 (not $e890))
+(flet ($e983 (if_then_else $e456 $e876 $e837))
+(flet ($e984 (not $e962))
+(flet ($e985 (and $e808 $e930))
+(flet ($e986 (not $e850))
+(flet ($e987 (xor $e377 $e472))
+(flet ($e988 (if_then_else $e973 $e904 $e980))
+(flet ($e989 (xor $e940 $e847))
+(flet ($e990 (if_then_else $e911 $e902 $e942))
+(flet ($e991 (if_then_else $e449 $e982 $e915))
+(flet ($e992 (xor $e580 $e987))
+(flet ($e993 (xor $e938 $e737))
+(flet ($e994 (implies $e953 $e954))
+(flet ($e995 (xor $e879 $e734))
+(flet ($e996 (if_then_else $e522 $e990 $e937))
+(flet ($e997 (or $e609 $e989))
+(flet ($e998 (not $e436))
+(flet ($e999 (if_then_else $e957 $e429 $e854))
+(flet ($e1000 (implies $e543 $e684))
+(flet ($e1001 (and $e984 $e715))
+(flet ($e1002 (or $e829 $e720))
+(flet ($e1003 (implies $e951 $e503))
+(flet ($e1004 (xor $e704 $e958))
+(flet ($e1005 (if_then_else $e42 $e908 $e988))
+(flet ($e1006 (or $e515 $e382))
+(flet ($e1007 (xor $e963 $e594))
+(flet ($e1008 (implies $e59 $e632))
+(flet ($e1009 (or $e568 $e517))
+(flet ($e1010 (xor $e504 $e991))
+(flet ($e1011 (and $e1002 $e556))
+(flet ($e1012 (if_then_else $e598 $e670 $e971))
+(flet ($e1013 (iff $e981 $e857))
+(flet ($e1014 (or $e929 $e986))
+(flet ($e1015 (not $e595))
+(flet ($e1016 (iff $e555 $e68))
+(flet ($e1017 (or $e918 $e960))
+(flet ($e1018 (iff $e856 $e939))
+(flet ($e1019 (implies $e497 $e665))
+(flet ($e1020 (implies $e921 $e906))
+(flet ($e1021 (xor $e897 $e969))
+(flet ($e1022 (and $e380 $e475))
+(flet ($e1023 (xor $e468 $e868))
+(flet ($e1024 (not $e903))
+(flet ($e1025 (not $e1007))
+(flet ($e1026 (or $e783 $e756))
+(flet ($e1027 (and $e733 $e512))
+(flet ($e1028 (not $e832))
+(flet ($e1029 (if_then_else $e1020 $e1028 $e610))
+(flet ($e1030 (xor $e731 $e673))
+(flet ($e1031 (not $e995))
+(flet ($e1032 (or $e1003 $e952))
+(flet ($e1033 (or $e1011 $e959))
+(flet ($e1034 (and $e1000 $e1013))
+(flet ($e1035 (and $e1016 $e427))
+(flet ($e1036 (xor $e985 $e534))
+(flet ($e1037 (and $e1010 $e881))
+(flet ($e1038 (xor $e1035 $e546))
+(flet ($e1039 (and $e1036 $e922))
+(flet ($e1040 (or $e855 $e506))
+(flet ($e1041 (if_then_else $e774 $e1008 $e925))
+(flet ($e1042 (implies $e975 $e752))
+(flet ($e1043 (and $e1034 $e907))
+(flet ($e1044 (or $e679 $e797))
+(flet ($e1045 (iff $e533 $e471))
+(flet ($e1046 (if_then_else $e993 $e645 $e605))
+(flet ($e1047 (implies $e67 $e1006))
+(flet ($e1048 (implies $e968 $e994))
+(flet ($e1049 (not $e579))
+(flet ($e1050 (if_then_else $e1005 $e1027 $e956))
+(flet ($e1051 (iff $e476 $e628))
+(flet ($e1052 (if_then_else $e926 $e1017 $e871))
+(flet ($e1053 (or $e936 $e1025))
+(flet ($e1054 (implies $e983 $e1053))
+(flet ($e1055 (implies $e977 $e978))
+(flet ($e1056 (iff $e588 $e698))
+(flet ($e1057 (or $e1019 $e999))
+(flet ($e1058 (and $e917 $e931))
+(flet ($e1059 (and $e972 $e432))
+(flet ($e1060 (xor $e979 $e457))
+(flet ($e1061 (and $e1018 $e923))
+(flet ($e1062 (if_then_else $e516 $e1047 $e708))
+(flet ($e1063 (not $e1050))
+(flet ($e1064 (and $e1048 $e886))
+(flet ($e1065 (implies $e815 $e815))
+(flet ($e1066 (iff $e1044 $e741))
+(flet ($e1067 (xor $e974 $e945))
+(flet ($e1068 (if_then_else $e1022 $e660 $e1056))
+(flet ($e1069 (if_then_else $e996 $e701 $e1049))
+(flet ($e1070 (implies $e1039 $e1059))
+(flet ($e1071 (not $e828))
+(flet ($e1072 (if_then_else $e404 $e550 $e852))
+(flet ($e1073 (and $e1065 $e386))
+(flet ($e1074 (or $e804 $e1040))
+(flet ($e1075 (not $e1057))
+(flet ($e1076 (implies $e1067 $e1033))
+(flet ($e1077 (or $e1068 $e1004))
+(flet ($e1078 (implies $e1072 $e1061))
+(flet ($e1079 (or $e1026 $e1021))
+(flet ($e1080 (xor $e1037 $e910))
+(flet ($e1081 (not $e37))
+(flet ($e1082 (xor $e1030 $e900))
+(flet ($e1083 (not $e671))
+(flet ($e1084 (implies $e666 $e697))
+(flet ($e1085 (and $e961 $e764))
+(flet ($e1086 (or $e1085 $e1063))
+(flet ($e1087 (implies $e892 $e680))
+(flet ($e1088 (iff $e1066 $e1069))
+(flet ($e1089 (or $e416 $e635))
+(flet ($e1090 (and $e1051 $e1080))
+(flet ($e1091 (or $e838 $e1073))
+(flet ($e1092 (iff $e1081 $e1060))
+(flet ($e1093 (or $e1086 $e1014))
+(flet ($e1094 (implies $e373 $e1024))
+(flet ($e1095 (and $e1038 $e1087))
+(flet ($e1096 (iff $e1054 $e573))
+(flet ($e1097 (if_then_else $e778 $e992 $e659))
+(flet ($e1098 (not $e552))
+(flet ($e1099 (xor $e913 $e781))
+(flet ($e1100 (xor $e899 $e998))
+(flet ($e1101 (or $e439 $e1074))
+(flet ($e1102 (xor $e1062 $e699))
+(flet ($e1103 (iff $e1052 $e967))
+(flet ($e1104 (and $e1070 $e935))
+(flet ($e1105 (if_then_else $e1029 $e976 $e976))
+(flet ($e1106 (implies $e1015 $e1090))
+(flet ($e1107 (xor $e1045 $e1084))
+(flet ($e1108 (iff $e1082 $e964))
+(flet ($e1109 (not $e1100))
+(flet ($e1110 (if_then_else $e1023 $e1091 $e1107))
+(flet ($e1111 (or $e743 $e747))
+(flet ($e1112 (implies $e1075 $e1094))
+(flet ($e1113 (if_then_else $e1104 $e1083 $e1103))
+(flet ($e1114 (and $e1076 $e501))
+(flet ($e1115 (iff $e1058 $e1092))
+(flet ($e1116 (xor $e748 $e1055))
+(flet ($e1117 (and $e1112 $e1089))
+(flet ($e1118 (not $e1102))
+(flet ($e1119 (if_then_else $e1116 $e65 $e1096))
+(flet ($e1120 (or $e1041 $e1119))
+(flet ($e1121 (or $e392 $e1109))
+(flet ($e1122 (iff $e1114 $e1106))
+(flet ($e1123 (or $e1078 $e965))
+(flet ($e1124 (or $e875 $e997))
+(flet ($e1125 (and $e407 $e1108))
+(flet ($e1126 (or $e1125 $e1043))
+(flet ($e1127 (iff $e1064 $e1117))
+(flet ($e1128 (iff $e1123 $e1042))
+(flet ($e1129 (xor $e1113 $e1124))
+(flet ($e1130 (and $e484 $e1127))
+(flet ($e1131 (iff $e1130 $e1079))
+(flet ($e1132 (implies $e1111 $e1046))
+(flet ($e1133 (implies $e1132 $e410))
+(flet ($e1134 (xor $e970 $e1071))
+(flet ($e1135 (implies $e1121 $e1122))
+(flet ($e1136 (and $e1120 $e1088))
+(flet ($e1137 (xor $e885 $e1093))
+(flet ($e1138 (or $e916 $e1118))
+(flet ($e1139 (implies $e1095 $e1115))
+(flet ($e1140 (if_then_else $e1098 $e1138 $e1126))
+(flet ($e1141 (xor $e1131 $e1131))
+(flet ($e1142 (not $e1032))
+(flet ($e1143 (and $e1141 $e1001))
+(flet ($e1144 (not $e866))
+(flet ($e1145 (not $e1128))
+(flet ($e1146 (iff $e1031 $e1139))
+(flet ($e1147 (not $e1137))
+(flet ($e1148 (and $e1077 $e1105))
+(flet ($e1149 (not $e1144))
+(flet ($e1150 (if_then_else $e1140 $e1009 $e1145))
+(flet ($e1151 (if_then_else $e1097 $e1143 $e1101))
+(flet ($e1152 (implies $e1134 $e1110))
+(flet ($e1153 (xor $e1142 $e1099))
+(flet ($e1154 (not $e1135))
+(flet ($e1155 (if_then_else $e1147 $e1149 $e1136))
+(flet ($e1156 (or $e1152 $e616))
+(flet ($e1157 (not $e1156))
+(flet ($e1158 (xor $e1148 $e1151))
+(flet ($e1159 (implies $e1153 $e1153))
+(flet ($e1160 (and $e1157 $e1133))
+(flet ($e1161 (or $e1154 $e1159))
+(flet ($e1162 (implies $e1155 $e1160))
+(flet ($e1163 (implies $e1162 $e1161))
+(flet ($e1164 (iff $e1163 $e1163))
+(flet ($e1165 (xor $e1146 $e1129))
+(flet ($e1166 (not $e1012))
+(flet ($e1167 (xor $e544 $e1166))
+(flet ($e1168 (iff $e1165 $e1150))
+(flet ($e1169 (xor $e1164 $e1158))
+(flet ($e1170 (if_then_else $e1167 $e1167 $e1169))
+(flet ($e1171 (not $e1168))
+(flet ($e1172 (and $e1171 $e1171))
+(flet ($e1173 (xor $e1170 $e1170))
+(flet ($e1174 (and $e1173 $e1173))
+(flet ($e1175 (iff $e1174 $e1174))
+(flet ($e1176 (xor $e1175 $e1175))
+(flet ($e1177 (implies $e1172 $e1172))
+(flet ($e1178 (and $e1176 $e1176))
+(flet ($e1179 (not $e1177))
+(flet ($e1180 (xor $e1179 $e1178))
+$e1180
+))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+
diff --git a/test/regress/regress0/decision/pp-regfile.smt.expect b/test/regress/regress0/decision/bug374a.smt.expect
index b862d0b39..b862d0b39 100644
--- a/test/regress/regress0/decision/pp-regfile.smt.expect
+++ b/test/regress/regress0/decision/bug374a.smt.expect
diff --git a/test/regress/regress0/decision/bug374b.smt2 b/test/regress/regress0/decision/bug374b.smt2
new file mode 100644
index 000000000..a253cf12f
--- /dev/null
+++ b/test/regress/regress0/decision/bug374b.smt2
@@ -0,0 +1,14 @@
+(set-logic QF_ALL_SUPPORTED)
+(declare-fun _substvar_245_ () Bool)
+(declare-fun _substvar_246_ () Bool)
+(declare-fun _substvar_247_ () Bool)
+(declare-fun group_size_x () (_ BitVec 32))
+(declare-fun group_id_x$2 () (_ BitVec 32))
+(declare-fun local_id_x$2 () (_ BitVec 32))
+(assert (= _substvar_245_ _substvar_246_))
+(assert
+ (and (bvsge group_id_x$2 #x00000000) (bvsge local_id_x$2 #x00000000) (bvslt local_id_x$2 group_size_x)
+ (or (not (bvsgt group_size_x #x00000000)) (not (and (=> _substvar_247_ (bvsge group_id_x$2 #x00000000)) (= _substvar_245_ _substvar_246_))))
+ )
+ )
+(check-sat)
diff --git a/test/regress/regress0/decision/bug374b.smt2.expect b/test/regress/regress0/decision/bug374b.smt2.expect
new file mode 100644
index 000000000..3e0839205
--- /dev/null
+++ b/test/regress/regress0/decision/bug374b.smt2.expect
@@ -0,0 +1,3 @@
+% COMMAND-LINE: --decision=justification --no-unconstrained
+% EXPECT: unsat
+% EXIT: 20
diff --git a/test/regress/regress0/fmf/ALG008-1.smt2 b/test/regress/regress0/fmf/ALG008-1.smt2
new file mode 100644
index 000000000..018006f45
--- /dev/null
+++ b/test/regress/regress0/fmf/ALG008-1.smt2
@@ -0,0 +1,73 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: sat
+; EXIT: 10
+;%--------------------------------------------------------------------------
+;% File : ALG008-1 : TPTP v5.4.0. Released v2.2.0.
+;% Domain : General Algebra
+;% Problem : TC + right identity does not give RC.
+;% Version : [MP96] (equality) axioms : Especial.
+;% English : An algebra with a right identity satisfying the Thomsen
+;% Closure (RC) condition does not necessarily satisfy the
+;% Reidemeister Closure (RC) condition.
+
+;% Refs : [McC98] McCune (1998), Email to G. Sutcliffe
+;% : [MP96] McCune & Padmanabhan (1996), Automated Deduction in Eq
+;% Source : [McC98]
+;% Names : TC-3 [MP96]
+
+;% Status : Satisfiable
+;% Rating : 0.50 v5.4.0, 0.80 v5.3.0, 0.78 v5.2.0, 0.80 v5.0.0, 0.78 v4.1.0, 0.71 v4.0.1, 0.80 v4.0.0, 0.50 v3.7.0, 0.33 v3.4.0, 0.50 v3.3.0, 0.33 v3.2.0, 0.80 v3.1.0, 0.67 v2.7.0, 0.33 v2.6.0, 0.86 v2.5.0, 0.50 v2.4.0, 0.67 v2.3.0, 1.00 v2.2.1
+;% Syntax : Number of clauses : 6 ( 0 non-Horn; 5 unit; 5 RR)
+;% Number of atoms : 10 ( 10 equality)
+;% Maximal clause size : 5 ( 2 average)
+;% Number of predicates : 1 ( 0 propositional; 2-2 arity)
+;% Number of functors : 9 ( 8 constant; 0-2 arity)
+;% Number of variables : 9 ( 0 singleton)
+;% Maximal term depth : 2 ( 2 average)
+;% SPC : CNF_SAT_RFO_EQU_NUE
+
+;% Comments : The smallest model has 3 elements.
+;%--------------------------------------------------------------------------
+;%----Thomsen Closure (TC) condition:
+(set-logic UF)
+(set-info :status sat)
+(declare-sort sort__smt2 0)
+; functions
+(declare-fun multiply__smt2_2 ( sort__smt2 sort__smt2 ) sort__smt2)
+(declare-fun identity__smt2_0 ( ) sort__smt2)
+(declare-fun c4__smt2_0 ( ) sort__smt2)
+(declare-fun a__smt2_0 ( ) sort__smt2)
+(declare-fun c3__smt2_0 ( ) sort__smt2)
+(declare-fun b__smt2_0 ( ) sort__smt2)
+(declare-fun c2__smt2_0 ( ) sort__smt2)
+(declare-fun c1__smt2_0 ( ) sort__smt2)
+(declare-fun f__smt2_0 ( ) sort__smt2)
+; predicates
+
+; thomsen_closure axiom
+(assert (forall ((?V7 sort__smt2) (?V6 sort__smt2) (?W sort__smt2) (?V sort__smt2) (?U sort__smt2) (?Z sort__smt2) (?Y sort__smt2) (?X sort__smt2))
+ (or (not (= (multiply__smt2_2 ?X ?Y) ?Z))
+ (not (= (multiply__smt2_2 ?U ?V) ?Z))
+ (not (= (multiply__smt2_2 ?X ?W) ?V6))
+ (not (= (multiply__smt2_2 ?V7 ?V) ?V6))
+ (= (multiply__smt2_2 ?U ?W) (multiply__smt2_2 ?V7 ?Y)))) )
+
+;%----Right identity:
+; right_identity axiom
+(assert (forall ((?X sort__smt2)) (= (multiply__smt2_2 ?X identity__smt2_0) ?X)) )
+
+;%----Denial of Reidimeister Closure (RC) condidition.
+; prove_reidimeister1 negated_conjecture
+(assert (= (multiply__smt2_2 c4__smt2_0 a__smt2_0) (multiply__smt2_2 c3__smt2_0 b__smt2_0)) )
+
+; prove_reidimeister2 negated_conjecture
+(assert (= (multiply__smt2_2 c2__smt2_0 a__smt2_0) (multiply__smt2_2 c1__smt2_0 b__smt2_0)) )
+
+; prove_reidimeister3 negated_conjecture
+(assert (= (multiply__smt2_2 c4__smt2_0 f__smt2_0) (multiply__smt2_2 c3__smt2_0 identity__smt2_0)) )
+
+; prove_reidimeister4 negated_conjecture
+(assert (not (= (multiply__smt2_2 c2__smt2_0 f__smt2_0) (multiply__smt2_2 c1__smt2_0 identity__smt2_0))) )
+
+
+(check-sat)
diff --git a/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt b/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt
new file mode 100644
index 000000000..644d29737
--- /dev/null
+++ b/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt
@@ -0,0 +1,265 @@
+% COMMAND-LINE: --finite-model-find
+% EXPECT: unsat
+% EXIT: 20
+(benchmark Isabelle
+:status sat
+:logic AUFLIA
+:extrasorts ( S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 S14 S15 S16 S17 S18 S19 S20 S21 S22 S23 S24 S25 S26 S27 S28 S29 S30 S31 S32 S33 S34 S35 S36 S37)
+:extrafuns (
+ (f1 S1)
+ (f2 S1)
+ (f3 S3 S2 S1)
+ (f4 S4 S2 S3)
+ (f5 S4)
+ (f6 S6 S5 S1)
+ (f7 S7 S5 S6)
+ (f8 S7)
+ (f9 S9 S8 S1)
+ (f10 S10 S8 S9)
+ (f11 S10)
+ (f12 S1)
+ (f13 S12 S1)
+ (f14 S12)
+ (f15 S12 S1)
+ (f16 S2)
+ (f17 S13 S2 S2)
+ (f18 S14 S11 S13)
+ (f19 S14)
+ (f20 S5)
+ (f21 S16 S5 S5)
+ (f22 S17 S15 S16)
+ (f23 S17)
+ (f24 S8)
+ (f25 S18 S8 S8)
+ (f26 S19 S5 S18)
+ (f27 S19)
+ (f28 S20 S2 S13)
+ (f29 S20)
+ (f30 S21 S5 S16)
+ (f31 S21)
+ (f32 S22 S8 S18)
+ (f33 S22)
+ (f34 S14)
+ (f35 S17)
+ (f36 S19)
+ (f37 S24 S23 S2)
+ (f38 S25 S2 S24)
+ (f39 S25)
+ (f40 S26 S23 S1)
+ (f41 S27 Int S26)
+ (f42 S27)
+ (f43 S28 S23 S5)
+ (f44 S29 S5 S28)
+ (f45 S29)
+ (f46 S30 S23 S8)
+ (f47 S31 S8 S30)
+ (f48 S31)
+ (f49 S2 S1)
+ (f50 S5 S1)
+ (f51 S8 S1)
+ (f52 S4)
+ (f53 S7)
+ (f54 S10)
+ (f55 S32 S2 S11)
+ (f56 S32)
+ (f57 S33 S5 S15)
+ (f58 S33)
+ (f59 S34 S8 S5)
+ (f60 S34)
+ (f61 S35 S11 S1)
+ (f62 S2 S35)
+ (f63 S36 S15 S1)
+ (f64 S5 S36)
+ (f65 S8 S6)
+ (f66 S35 S3)
+ (f67 S36 S6)
+ (f68 S6 S9)
+ (f69 S11 S3)
+ (f70 S5 S9)
+ (f71 S15 S6)
+ (f72 S13)
+ (f73 S16)
+ (f74 S18)
+ (f75 S20)
+ (f76 S21)
+ (f77 S22)
+ (f78 S37 S26 Int)
+ (f79 S37)
+)
+:assumption (not (= f1 f2))
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= (f3 (f4 f5 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S5) (?v1 S5) (iff (= (f6 (f7 f8 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S8) (?v1 S8) (iff (= (f9 (f10 f11 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (not (= f12 f1))
+:assumption (forall (?v0 S11) (?v1 S11) (implies (not (= ?v0 ?v1)) (= f12 f1)))
+:assumption (exists (?v0 S11) (?v1 S11) (?v2 S11) (distinct ?v0 ?v1 ?v2))
+:assumption (exists (?v0 S11) (?v1 S11) (?v2 S11) (distinct ?v0 ?v1 ?v2) )
+:assumption (= (f13 f14) f1)
+:assumption (= (f15 f14) f1)
+:assumption (forall (?v0 S11) (?v1 S11) (implies (not (= ?v0 ?v1)) (exists (?v2 S11) (distinct ?v0 ?v1 ?v2))) )
+:assumption (forall (?v0 S11) (?v1 S2) (not (= f16 (f17 (f18 f19 ?v0) ?v1))) )
+:assumption (forall (?v0 S15) (?v1 S5) (not (= f20 (f21 (f22 f23 ?v0) ?v1))) )
+:assumption (forall (?v0 S5) (?v1 S8) (not (= f24 (f25 (f26 f27 ?v0) ?v1))) )
+:assumption (forall (?v0 S11) (?v1 S2) (not (= (f17 (f18 f19 ?v0) ?v1) f16)) )
+:assumption (forall (?v0 S15) (?v1 S5) (not (= (f21 (f22 f23 ?v0) ?v1) f20)) )
+:assumption (forall (?v0 S5) (?v1 S8) (not (= (f25 (f26 f27 ?v0) ?v1) f24)) )
+:assumption (forall (?v0 S2) (iff (not (= ?v0 f16)) (exists (?v1 S11) (?v2 S2) (= ?v0 (f17 (f18 f19 ?v1) ?v2)))) )
+:assumption (forall (?v0 S5) (iff (not (= ?v0 f20)) (exists (?v1 S15) (?v2 S5) (= ?v0 (f21 (f22 f23 ?v1) ?v2)))) )
+:assumption (forall (?v0 S8) (iff (not (= ?v0 f24)) (exists (?v1 S5) (?v2 S8) (= ?v0 (f25 (f26 f27 ?v1) ?v2)))) )
+:assumption (forall (?v0 S2) (implies (implies (= ?v0 f16) false) (implies (forall (?v1 S11) (?v2 S2) (implies (= ?v0 (f17 (f18 f19 ?v1) ?v2)) false)) false)) )
+:assumption (forall (?v0 S5) (implies (implies (= ?v0 f20) false) (implies (forall (?v1 S15) (?v2 S5) (implies (= ?v0 (f21 (f22 f23 ?v1) ?v2)) false)) false)) )
+:assumption (forall (?v0 S8) (implies (implies (= ?v0 f24) false) (implies (forall (?v1 S5) (?v2 S8) (implies (= ?v0 (f25 (f26 f27 ?v1) ?v2)) false)) false)) )
+:assumption (forall (?v0 S2) (?v1 S11) (not (= ?v0 (f17 (f18 f19 ?v1) ?v0))) )
+:assumption (forall (?v0 S8) (?v1 S5) (not (= ?v0 (f25 (f26 f27 ?v1) ?v0))) )
+:assumption (forall (?v0 S5) (?v1 S15) (not (= ?v0 (f21 (f22 f23 ?v1) ?v0))) )
+:assumption (forall (?v0 S11) (?v1 S2) (not (= (f17 (f18 f19 ?v0) ?v1) ?v1)) )
+:assumption (forall (?v0 S5) (?v1 S8) (not (= (f25 (f26 f27 ?v0) ?v1) ?v1)) )
+:assumption (forall (?v0 S15) (?v1 S5) (not (= (f21 (f22 f23 ?v0) ?v1) ?v1)) )
+:assumption (forall (?v0 S11) (?v1 S2) (?v2 S11) (?v3 S2) (iff (= (f17 (f18 f19 ?v0) ?v1) (f17 (f18 f19 ?v2) ?v3)) (and (= ?v0 ?v2) (= ?v1 ?v3))) )
+:assumption (forall (?v0 S5) (?v1 S8) (?v2 S5) (?v3 S8) (iff (= (f25 (f26 f27 ?v0) ?v1) (f25 (f26 f27 ?v2) ?v3)) (and (= ?v0 ?v2) (= ?v1 ?v3))) )
+:assumption (forall (?v0 S15) (?v1 S5) (?v2 S15) (?v3 S5) (iff (= (f21 (f22 f23 ?v0) ?v1) (f21 (f22 f23 ?v2) ?v3)) (and (= ?v0 ?v2) (= ?v1 ?v3))) )
+:assumption (forall (?v0 S11) (?v1 S2) (= (f17 (f28 f29 (f17 (f18 f19 ?v0) ?v1)) f16) (f17 (f18 f19 ?v0) ?v1)) )
+:assumption (forall (?v0 S15) (?v1 S5) (= (f21 (f30 f31 (f21 (f22 f23 ?v0) ?v1)) f20) (f21 (f22 f23 ?v0) ?v1)) )
+:assumption (forall (?v0 S5) (?v1 S8) (= (f25 (f32 f33 (f25 (f26 f27 ?v0) ?v1)) f24) (f25 (f26 f27 ?v0) ?v1)) )
+:assumption (forall (?v0 S11) (= (f17 (f18 f34 ?v0) f16) (f17 (f18 f19 ?v0) f16)) )
+:assumption (forall (?v0 S15) (= (f21 (f22 f35 ?v0) f20) (f21 (f22 f23 ?v0) f20)) )
+:assumption (forall (?v0 S5) (= (f25 (f26 f36 ?v0) f24) (f25 (f26 f27 ?v0) f24)) )
+:assumption (forall (?v0 S2) (?v1 S3) (implies (not (= ?v0 f16)) (implies (forall (?v2 S11) (= (f3 ?v1 (f17 (f18 f19 ?v2) f16)) f1)) (implies (forall (?v2 S11) (?v3 S2) (implies (not (= ?v3 f16)) (implies (= (f3 ?v1 ?v3) f1) (= (f3 ?v1 (f17 (f18 f19 ?v2) ?v3)) f1)))) (= (f3 ?v1 ?v0) f1)))) )
+:assumption (forall (?v0 S5) (?v1 S6) (implies (not (= ?v0 f20)) (implies (forall (?v2 S15) (= (f6 ?v1 (f21 (f22 f23 ?v2) f20)) f1)) (implies (forall (?v2 S15) (?v3 S5) (implies (not (= ?v3 f20)) (implies (= (f6 ?v1 ?v3) f1) (= (f6 ?v1 (f21 (f22 f23 ?v2) ?v3)) f1)))) (= (f6 ?v1 ?v0) f1)))) )
+:assumption (forall (?v0 S8) (?v1 S9) (implies (not (= ?v0 f24)) (implies (forall (?v2 S5) (= (f9 ?v1 (f25 (f26 f27 ?v2) f24)) f1)) (implies (forall (?v2 S5) (?v3 S8) (implies (not (= ?v3 f24)) (implies (= (f9 ?v1 ?v3) f1) (= (f9 ?v1 (f25 (f26 f27 ?v2) ?v3)) f1)))) (= (f9 ?v1 ?v0) f1)))) )
+:assumption (forall (?v0 S11) (?v1 S23) (= (f37 (f38 f39 (f17 (f18 f19 ?v0) f16)) ?v1) (ite (= (f40 (f41 f42 0) ?v1) f1) (f17 (f18 f19 ?v0) f16) f16)) )
+:assumption (forall (?v0 S15) (?v1 S23) (= (f43 (f44 f45 (f21 (f22 f23 ?v0) f20)) ?v1) (ite (= (f40 (f41 f42 0) ?v1) f1) (f21 (f22 f23 ?v0) f20) f20)) )
+:assumption (forall (?v0 S5) (?v1 S23) (= (f46 (f47 f48 (f25 (f26 f27 ?v0) f24)) ?v1) (ite (= (f40 (f41 f42 0) ?v1) f1) (f25 (f26 f27 ?v0) f24) f24)) )
+:assumption (forall (?v0 S23) (= (f37 (f38 f39 f16) ?v0) f16) )
+:assumption (forall (?v0 S23) (= (f43 (f44 f45 f20) ?v0) f20) )
+:assumption (forall (?v0 S23) (= (f46 (f47 f48 f24) ?v0) f24) )
+:assumption (forall (?v0 S11) (?v1 S2) (?v2 S11) (?v3 S2) (= (f17 (f28 f29 (f17 (f18 f19 ?v0) ?v1)) (f17 (f18 f19 ?v2) ?v3)) (f17 (f18 f19 ?v0) (f17 (f18 f19 ?v2) (f17 (f28 f29 ?v1) ?v3)))) )
+:assumption (forall (?v0 S5) (?v1 S8) (?v2 S5) (?v3 S8) (= (f25 (f32 f33 (f25 (f26 f27 ?v0) ?v1)) (f25 (f26 f27 ?v2) ?v3)) (f25 (f26 f27 ?v0) (f25 (f26 f27 ?v2) (f25 (f32 f33 ?v1) ?v3)))) )
+:assumption (forall (?v0 S15) (?v1 S5) (?v2 S15) (?v3 S5) (= (f21 (f30 f31 (f21 (f22 f23 ?v0) ?v1)) (f21 (f22 f23 ?v2) ?v3)) (f21 (f22 f23 ?v0) (f21 (f22 f23 ?v2) (f21 (f30 f31 ?v1) ?v3)))) )
+:assumption (forall (?v0 S2) (= (f17 (f28 f29 ?v0) f16) ?v0) )
+:assumption (forall (?v0 S5) (= (f21 (f30 f31 ?v0) f20) ?v0) )
+:assumption (forall (?v0 S8) (= (f25 (f32 f33 ?v0) f24) ?v0) )
+:assumption (forall (?v0 S2) (= (f17 (f28 f29 f16) ?v0) ?v0) )
+:assumption (forall (?v0 S5) (= (f21 (f30 f31 f20) ?v0) ?v0) )
+:assumption (forall (?v0 S8) (= (f25 (f32 f33 f24) ?v0) ?v0) )
+:assumption (forall (?v0 S2) (iff (= ?v0 f16) (= (f49 ?v0) f1)) )
+:assumption (forall (?v0 S5) (iff (= ?v0 f20) (= (f50 ?v0) f1)) )
+:assumption (forall (?v0 S8) (iff (= ?v0 f24) (= (f51 ?v0) f1)) )
+:assumption (forall (?v0 S2) (iff (= (f49 ?v0) f1) (= ?v0 f16)) )
+:assumption (forall (?v0 S5) (iff (= (f50 ?v0) f1) (= ?v0 f20)) )
+:assumption (forall (?v0 S8) (iff (= (f51 ?v0) f1) (= ?v0 f24)) )
+:assumption (iff (= (f49 f16) f1) true)
+:assumption (iff (= (f50 f20) f1) true)
+:assumption (iff (= (f51 f24) f1) true)
+:assumption (forall (?v0 S11) (?v1 S2) (iff (= (f49 (f17 (f18 f19 ?v0) ?v1)) f1) false) )
+:assumption (forall (?v0 S5) (?v1 S8) (iff (= (f51 (f25 (f26 f27 ?v0) ?v1)) f1) false) )
+:assumption (forall (?v0 S15) (?v1 S5) (iff (= (f50 (f21 (f22 f23 ?v0) ?v1)) f1) false) )
+:assumption (forall (?v0 S2) (iff (= (f3 (f4 f52 ?v0) f16) f1) (= (f49 ?v0) f1)) )
+:assumption (forall (?v0 S5) (iff (= (f6 (f7 f53 ?v0) f20) f1) (= (f50 ?v0) f1)) )
+:assumption (forall (?v0 S8) (iff (= (f9 (f10 f54 ?v0) f24) f1) (= (f51 ?v0) f1)) )
+:assumption (forall (?v0 S11) (?v1 S2) (= (f55 f56 (f17 (f18 f19 ?v0) ?v1)) (ite (= ?v1 f16) ?v0 (f55 f56 ?v1))) )
+:assumption (forall (?v0 S15) (?v1 S5) (= (f57 f58 (f21 (f22 f23 ?v0) ?v1)) (ite (= ?v1 f20) ?v0 (f57 f58 ?v1))) )
+:assumption (forall (?v0 S5) (?v1 S8) (= (f59 f60 (f25 (f26 f27 ?v0) ?v1)) (ite (= ?v1 f24) ?v0 (f59 f60 ?v1))) )
+:assumption (forall (?v0 S2) (?v1 S11) (implies (not (= ?v0 f16)) (= (f55 f56 (f17 (f18 f19 ?v1) ?v0)) (f55 f56 ?v0))) )
+:assumption (forall (?v0 S5) (?v1 S15) (implies (not (= ?v0 f20)) (= (f57 f58 (f21 (f22 f23 ?v1) ?v0)) (f57 f58 ?v0))) )
+:assumption (forall (?v0 S8) (?v1 S5) (implies (not (= ?v0 f24)) (= (f59 f60 (f25 (f26 f27 ?v1) ?v0)) (f59 f60 ?v0))) )
+:assumption (forall (?v0 S2) (?v1 S11) (implies (= ?v0 f16) (= (f55 f56 (f17 (f18 f19 ?v1) ?v0)) ?v1)) )
+:assumption (forall (?v0 S5) (?v1 S15) (implies (= ?v0 f20) (= (f57 f58 (f21 (f22 f23 ?v1) ?v0)) ?v1)) )
+:assumption (forall (?v0 S8) (?v1 S5) (implies (= ?v0 f24) (= (f59 f60 (f25 (f26 f27 ?v1) ?v0)) ?v1)) )
+:assumption (forall (?v0 S11) (iff (= (f61 (f62 f16) ?v0) f1) false) )
+:assumption (forall (?v0 S15) (iff (= (f63 (f64 f20) ?v0) f1) false) )
+:assumption (forall (?v0 S5) (iff (= (f6 (f65 f24) ?v0) f1) false) )
+:assumption (forall (?v0 S35) (iff (= (f3 (f66 ?v0) f16) f1) false) )
+:assumption (forall (?v0 S36) (iff (= (f6 (f67 ?v0) f20) f1) false) )
+:assumption (forall (?v0 S6) (iff (= (f9 (f68 ?v0) f24) f1) false) )
+:assumption (forall (?v0 S11) (?v1 S2) (= (f3 (f69 ?v0) (f17 (f18 f19 ?v0) ?v1)) f1) )
+:assumption (forall (?v0 S5) (?v1 S8) (= (f9 (f70 ?v0) (f25 (f26 f27 ?v0) ?v1)) f1) )
+:assumption (forall (?v0 S15) (?v1 S5) (= (f6 (f71 ?v0) (f21 (f22 f23 ?v0) ?v1)) f1) )
+:assumption (forall (?v0 S11) (?v1 S2) (?v2 S11) (iff (= (f61 (f62 (f17 (f18 f19 ?v0) ?v1)) ?v2) f1) (or (= ?v0 ?v2) (= (f61 (f62 ?v1) ?v2) f1))) )
+:assumption (forall (?v0 S5) (?v1 S8) (?v2 S5) (iff (= (f6 (f65 (f25 (f26 f27 ?v0) ?v1)) ?v2) f1) (or (= ?v0 ?v2) (= (f6 (f65 ?v1) ?v2) f1))) )
+:assumption (forall (?v0 S15) (?v1 S5) (?v2 S15) (iff (= (f63 (f64 (f21 (f22 f23 ?v0) ?v1)) ?v2) f1) (or (= ?v0 ?v2) (= (f63 (f64 ?v1) ?v2) f1))) )
+:assumption (forall (?v0 S8) (?v1 S8) (iff (= (f9 (f10 f54 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S5) (?v1 S5) (iff (= (f6 (f7 f53 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= (f3 (f4 f52 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (= (f17 f72 f16) f16)
+:assumption (= (f21 f73 f20) f20)
+:assumption (= (f25 f74 f24) f24)
+:assumption (forall (?v0 S11) (?v1 S2) (= (f17 f72 (f17 (f18 f19 ?v0) ?v1)) (ite (= ?v1 f16) f16 (f17 (f18 f19 ?v0) (f17 f72 ?v1)))) )
+:assumption (forall (?v0 S15) (?v1 S5) (= (f21 f73 (f21 (f22 f23 ?v0) ?v1)) (ite (= ?v1 f20) f20 (f21 (f22 f23 ?v0) (f21 f73 ?v1)))) )
+:assumption (forall (?v0 S5) (?v1 S8) (= (f25 f74 (f25 (f26 f27 ?v0) ?v1)) (ite (= ?v1 f24) f24 (f25 (f26 f27 ?v0) (f25 f74 ?v1)))) )
+:assumption (forall (?v0 S11) (?v1 S2) (?v2 S11) (implies (= (f3 (f69 ?v0) ?v1) f1) (= (f3 (f69 ?v0) (f17 (f18 f19 ?v2) ?v1)) f1)) )
+:assumption (forall (?v0 S5) (?v1 S8) (?v2 S5) (implies (= (f9 (f70 ?v0) ?v1) f1) (= (f9 (f70 ?v0) (f25 (f26 f27 ?v2) ?v1)) f1)) )
+:assumption (forall (?v0 S15) (?v1 S5) (?v2 S15) (implies (= (f6 (f71 ?v0) ?v1) f1) (= (f6 (f71 ?v0) (f21 (f22 f23 ?v2) ?v1)) f1)) )
+:assumption (forall (?v0 S2) (implies (not (= ?v0 f16)) (= (f17 (f28 f75 (f17 f72 ?v0)) (f17 (f18 f19 (f55 f56 ?v0)) f16)) ?v0)) )
+:assumption (forall (?v0 S5) (implies (not (= ?v0 f20)) (= (f21 (f30 f76 (f21 f73 ?v0)) (f21 (f22 f23 (f57 f58 ?v0)) f20)) ?v0)) )
+:assumption (forall (?v0 S8) (implies (not (= ?v0 f24)) (= (f25 (f32 f77 (f25 f74 ?v0)) (f25 (f26 f27 (f59 f60 ?v0)) f24)) ?v0)) )
+:assumption (forall (?v0 S2) (?v1 S11) (?v2 S2) (iff (= (f17 (f28 f75 ?v0) (f17 (f18 f19 ?v1) f16)) ?v2) (and (not (= ?v2 f16)) (and (= (f17 f72 ?v2) ?v0) (= (f55 f56 ?v2) ?v1)))) )
+:assumption (forall (?v0 S5) (?v1 S15) (?v2 S5) (iff (= (f21 (f30 f76 ?v0) (f21 (f22 f23 ?v1) f20)) ?v2) (and (not (= ?v2 f20)) (and (= (f21 f73 ?v2) ?v0) (= (f57 f58 ?v2) ?v1)))) )
+:assumption (forall (?v0 S8) (?v1 S5) (?v2 S8) (iff (= (f25 (f32 f77 ?v0) (f25 (f26 f27 ?v1) f24)) ?v2) (and (not (= ?v2 f24)) (and (= (f25 f74 ?v2) ?v0) (= (f59 f60 ?v2) ?v1)))) )
+:assumption (= f11 f54)
+:assumption (= f8 f53)
+:assumption (= f5 f52)
+:assumption (forall (?v0 S8) (?v1 S8) (iff (= (f9 (f10 f54 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S5) (?v1 S5) (iff (= (f6 (f7 f53 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= (f3 (f4 f52 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S8) (iff (= (f9 (f10 f54 ?v0) ?v0) f1) true) )
+:assumption (forall (?v0 S5) (iff (= (f6 (f7 f53 ?v0) ?v0) f1) true) )
+:assumption (forall (?v0 S2) (iff (= (f3 (f4 f52 ?v0) ?v0) f1) true) )
+:assumption (= f54 f11)
+:assumption (= f53 f8)
+:assumption (= f52 f5)
+:assumption (forall (?v0 S11) (?v1 S2) (iff (= (f3 (f69 ?v0) ?v1) f1) (or (exists (?v2 S11) (?v3 S2) (and (= ?v0 ?v2) (= ?v1 (f17 (f18 f19 ?v2) ?v3)))) (exists (?v2 S11) (?v3 S2) (?v4 S11) (and (= ?v0 ?v2) (and (= ?v1 (f17 (f18 f19 ?v4) ?v3)) (= (f3 (f69 ?v2) ?v3) f1)))))) )
+:assumption (forall (?v0 S5) (?v1 S8) (iff (= (f9 (f70 ?v0) ?v1) f1) (or (exists (?v2 S5) (?v3 S8) (and (= ?v0 ?v2) (= ?v1 (f25 (f26 f27 ?v2) ?v3)))) (exists (?v2 S5) (?v3 S8) (?v4 S5) (and (= ?v0 ?v2) (and (= ?v1 (f25 (f26 f27 ?v4) ?v3)) (= (f9 (f70 ?v2) ?v3) f1)))))) )
+:assumption (forall (?v0 S15) (?v1 S5) (iff (= (f6 (f71 ?v0) ?v1) f1) (or (exists (?v2 S15) (?v3 S5) (and (= ?v0 ?v2) (= ?v1 (f21 (f22 f23 ?v2) ?v3)))) (exists (?v2 S15) (?v3 S5) (?v4 S15) (and (= ?v0 ?v2) (and (= ?v1 (f21 (f22 f23 ?v4) ?v3)) (= (f6 (f71 ?v2) ?v3) f1)))))) )
+:assumption (forall (?v0 S2) (?v1 S11) (= (f55 f56 (f17 (f28 f75 ?v0) (f17 (f18 f19 ?v1) f16))) ?v1) )
+:assumption (forall (?v0 S5) (?v1 S15) (= (f57 f58 (f21 (f30 f76 ?v0) (f21 (f22 f23 ?v1) f20))) ?v1) )
+:assumption (forall (?v0 S8) (?v1 S5) (= (f59 f60 (f25 (f32 f77 ?v0) (f25 (f26 f27 ?v1) f24))) ?v1) )
+:assumption (forall (?v0 S8) (?v1 S8) (?v2 S8) (?v3 S8) (?v4 S8) (implies (= (f25 (f32 f77 ?v0) ?v1) ?v2) (implies (= ?v3 (f25 (f32 f77 ?v1) ?v4)) (= (f25 (f32 f77 ?v0) ?v3) (f25 (f32 f77 ?v2) ?v4)))) )
+:assumption (forall (?v0 S5) (?v1 S5) (?v2 S5) (?v3 S5) (?v4 S5) (implies (= (f21 (f30 f76 ?v0) ?v1) ?v2) (implies (= ?v3 (f21 (f30 f76 ?v1) ?v4)) (= (f21 (f30 f76 ?v0) ?v3) (f21 (f30 f76 ?v2) ?v4)))) )
+:assumption (forall (?v0 S2) (?v1 S2) (?v2 S2) (?v3 S2) (?v4 S2) (implies (= (f17 (f28 f75 ?v0) ?v1) ?v2) (implies (= ?v3 (f17 (f28 f75 ?v1) ?v4)) (= (f17 (f28 f75 ?v0) ?v3) (f17 (f28 f75 ?v2) ?v4)))) )
+:assumption (forall (?v0 S8) (?v1 S8) (?v2 S8) (iff (= (f25 (f32 f77 ?v0) ?v1) (f25 (f32 f77 ?v2) ?v1)) (= ?v0 ?v2)) )
+:assumption (forall (?v0 S5) (?v1 S5) (?v2 S5) (iff (= (f21 (f30 f76 ?v0) ?v1) (f21 (f30 f76 ?v2) ?v1)) (= ?v0 ?v2)) )
+:assumption (forall (?v0 S2) (?v1 S2) (?v2 S2) (iff (= (f17 (f28 f75 ?v0) ?v1) (f17 (f28 f75 ?v2) ?v1)) (= ?v0 ?v2)) )
+:assumption (forall (?v0 S8) (?v1 S8) (?v2 S8) (iff (= (f25 (f32 f77 ?v0) ?v1) (f25 (f32 f77 ?v0) ?v2)) (= ?v1 ?v2)) )
+:assumption (forall (?v0 S5) (?v1 S5) (?v2 S5) (iff (= (f21 (f30 f76 ?v0) ?v1) (f21 (f30 f76 ?v0) ?v2)) (= ?v1 ?v2)) )
+:assumption (forall (?v0 S2) (?v1 S2) (?v2 S2) (iff (= (f17 (f28 f75 ?v0) ?v1) (f17 (f28 f75 ?v0) ?v2)) (= ?v1 ?v2)) )
+:assumption (forall (?v0 S8) (?v1 S8) (?v2 S8) (?v3 S8) (iff (= (f25 (f32 f77 ?v0) ?v1) (f25 (f32 f77 ?v2) ?v3)) (exists (?v4 S8) (or (and (= ?v0 (f25 (f32 f77 ?v2) ?v4)) (= (f25 (f32 f77 ?v4) ?v1) ?v3)) (and (= (f25 (f32 f77 ?v0) ?v4) ?v2) (= ?v1 (f25 (f32 f77 ?v4) ?v3)))))) )
+:assumption (forall (?v0 S5) (?v1 S5) (?v2 S5) (?v3 S5) (iff (= (f21 (f30 f76 ?v0) ?v1) (f21 (f30 f76 ?v2) ?v3)) (exists (?v4 S5) (or (and (= ?v0 (f21 (f30 f76 ?v2) ?v4)) (= (f21 (f30 f76 ?v4) ?v1) ?v3)) (and (= (f21 (f30 f76 ?v0) ?v4) ?v2) (= ?v1 (f21 (f30 f76 ?v4) ?v3)))))) )
+:assumption (forall (?v0 S2) (?v1 S2) (?v2 S2) (?v3 S2) (iff (= (f17 (f28 f75 ?v0) ?v1) (f17 (f28 f75 ?v2) ?v3)) (exists (?v4 S2) (or (and (= ?v0 (f17 (f28 f75 ?v2) ?v4)) (= (f17 (f28 f75 ?v4) ?v1) ?v3)) (and (= (f17 (f28 f75 ?v0) ?v4) ?v2) (= ?v1 (f17 (f28 f75 ?v4) ?v3)))))) )
+:assumption (forall (?v0 S8) (?v1 S8) (?v2 S8) (= (f25 (f32 f77 (f25 (f32 f77 ?v0) ?v1)) ?v2) (f25 (f32 f77 ?v0) (f25 (f32 f77 ?v1) ?v2))) )
+:assumption (forall (?v0 S5) (?v1 S5) (?v2 S5) (= (f21 (f30 f76 (f21 (f30 f76 ?v0) ?v1)) ?v2) (f21 (f30 f76 ?v0) (f21 (f30 f76 ?v1) ?v2))) )
+:assumption (forall (?v0 S2) (?v1 S2) (?v2 S2) (= (f17 (f28 f75 (f17 (f28 f75 ?v0) ?v1)) ?v2) (f17 (f28 f75 ?v0) (f17 (f28 f75 ?v1) ?v2))) )
+:assumption (forall (?v0 S11) (?v1 S2) (?v2 S2) (= (f17 (f28 f75 (f17 (f18 f19 ?v0) ?v1)) ?v2) (f17 (f18 f19 ?v0) (f17 (f28 f75 ?v1) ?v2))) )
+:assumption (forall (?v0 S5) (?v1 S8) (?v2 S8) (= (f25 (f32 f77 (f25 (f26 f27 ?v0) ?v1)) ?v2) (f25 (f26 f27 ?v0) (f25 (f32 f77 ?v1) ?v2))) )
+:assumption (forall (?v0 S15) (?v1 S5) (?v2 S5) (= (f21 (f30 f76 (f21 (f22 f23 ?v0) ?v1)) ?v2) (f21 (f22 f23 ?v0) (f21 (f30 f76 ?v1) ?v2))) )
+:assumption (forall (?v0 S11) (?v1 S2) (?v2 S2) (?v3 S2) (?v4 S2) (implies (= (f17 (f18 f19 ?v0) ?v1) ?v2) (implies (= ?v3 (f17 (f28 f75 ?v1) ?v4)) (= (f17 (f18 f19 ?v0) ?v3) (f17 (f28 f75 ?v2) ?v4)))) )
+:assumption (forall (?v0 S5) (?v1 S8) (?v2 S8) (?v3 S8) (?v4 S8) (implies (= (f25 (f26 f27 ?v0) ?v1) ?v2) (implies (= ?v3 (f25 (f32 f77 ?v1) ?v4)) (= (f25 (f26 f27 ?v0) ?v3) (f25 (f32 f77 ?v2) ?v4)))) )
+:assumption (forall (?v0 S15) (?v1 S5) (?v2 S5) (?v3 S5) (?v4 S5) (implies (= (f21 (f22 f23 ?v0) ?v1) ?v2) (implies (= ?v3 (f21 (f30 f76 ?v1) ?v4)) (= (f21 (f22 f23 ?v0) ?v3) (f21 (f30 f76 ?v2) ?v4)))) )
+:assumption (forall (?v0 S2) (= (f17 (f28 f75 f16) ?v0) ?v0) )
+:assumption (forall (?v0 S5) (= (f21 (f30 f76 f20) ?v0) ?v0) )
+:assumption (forall (?v0 S8) (= (f25 (f32 f77 f24) ?v0) ?v0) )
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= f16 (f17 (f28 f75 ?v0) ?v1)) (and (= ?v0 f16) (= ?v1 f16))) )
+:assumption (forall (?v0 S5) (?v1 S5) (iff (= f20 (f21 (f30 f76 ?v0) ?v1)) (and (= ?v0 f20) (= ?v1 f20))) )
+:assumption (forall (?v0 S8) (?v1 S8) (iff (= f24 (f25 (f32 f77 ?v0) ?v1)) (and (= ?v0 f24) (= ?v1 f24))) )
+:assumption (forall (?v0 S2) (= (f17 (f28 f75 ?v0) f16) ?v0) )
+:assumption (forall (?v0 S5) (= (f21 (f30 f76 ?v0) f20) ?v0) )
+:assumption (forall (?v0 S8) (= (f25 (f32 f77 ?v0) f24) ?v0) )
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= ?v0 (f17 (f28 f75 ?v0) ?v1)) (= ?v1 f16)) )
+:assumption (forall (?v0 S5) (?v1 S5) (iff (= ?v0 (f21 (f30 f76 ?v0) ?v1)) (= ?v1 f20)) )
+:assumption (forall (?v0 S8) (?v1 S8) (iff (= ?v0 (f25 (f32 f77 ?v0) ?v1)) (= ?v1 f24)) )
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= ?v0 (f17 (f28 f75 ?v1) ?v0)) (= ?v1 f16)) )
+:assumption (forall (?v0 S5) (?v1 S5) (iff (= ?v0 (f21 (f30 f76 ?v1) ?v0)) (= ?v1 f20)) )
+:assumption (forall (?v0 S8) (?v1 S8) (iff (= ?v0 (f25 (f32 f77 ?v1) ?v0)) (= ?v1 f24)) )
+:assumption (forall (?v0 S26) (= (f41 f42 (f78 f79 ?v0)) ?v0))
+:assumption (forall (?v0 Int) (implies (<= 0 ?v0) (= (f78 f79 (f41 f42 ?v0)) ?v0)))
+:assumption (forall (?v0 Int) (implies (< ?v0 0) (= (f78 f79 (f41 f42 ?v0)) 0)))
+:formula true)
+; solver: z3
+; timeout: 5.0
+; random seed: 1
+; arguments:
+; DISPLAY_PROOF=true
+; PROOF_MODE=2
+; -rs:1
+; MODEL=true
+; -smt
diff --git a/test/regress/regress0/fmf/Hoare-z3.931718.smt b/test/regress/regress0/fmf/Hoare-z3.931718.smt
new file mode 100644
index 000000000..0b6fd0349
--- /dev/null
+++ b/test/regress/regress0/fmf/Hoare-z3.931718.smt
@@ -0,0 +1,50 @@
+% COMMAND-LINE: --finite-model-find
+% EXPECT: sat
+% EXIT: 10
+(benchmark Isabelle
+:status sat
+:logic AUFLIA
+:extrasorts ( S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11)
+:extrafuns (
+ (f1 S1)
+ (f2 S1)
+ (f3 S3 S2 S1)
+ (f4 S4 S2 S3)
+ (f5 S4)
+ (f6 S5 S5 S1)
+ (f7 S5)
+ (f8 S6 S5 S5)
+ (f9 S7 S6)
+ (f10 S8 S4 S7)
+ (f11 S9 S10 S8)
+ (f12 S11 S4 S9)
+ (f13 S11)
+ (f14 S4)
+ (f15 S10)
+ (f16 S4)
+ (f17 S10 S4)
+ (f18 S5 S5 S1)
+)
+:assumption (not (= f1 f2))
+:assumption (forall (?v0 S2) (?v1 S2) (iff (= (f3 (f4 f5 ?v0) ?v1) f1) (= ?v0 ?v1)) )
+:assumption (not (= (f6 f7 (f8 (f9 (f10 (f11 (f12 f13 f14) f15) f16)) f7)) f1))
+:assumption (= (f6 f7 (f8 (f9 (f10 (f11 (f12 f13 f5) f15) (f17 f15))) f7)) f1)
+:assumption (= (f18 f7 (f8 (f9 (f10 (f11 (f12 f13 f14) f15) f16)) f7)) f1)
+:assumption (forall (?v0 S5) (= (f6 ?v0 f7) f1) )
+:assumption (forall (?v0 S4) (?v1 S10) (?v2 S4) (?v3 S4) (?v4 S10) (?v5 S4) (iff (= (f10 (f11 (f12 f13 ?v0) ?v1) ?v2) (f10 (f11 (f12 f13 ?v3) ?v4) ?v5)) (and (= ?v0 ?v3) (and (= ?v1 ?v4) (= ?v2 ?v5)))) )
+:assumption (forall (?v0 S5) (?v1 S5) (implies (= (f6 ?v0 ?v1) f1) (= (f18 ?v0 ?v1) f1)) )
+:assumption (forall (?v0 S5) (?v1 S5) (?v2 S5) (implies (= (f6 ?v0 ?v1) f1) (implies (= (f6 ?v2 ?v0) f1) (= (f6 ?v2 ?v1) f1))) )
+:assumption (forall (?v0 S5) (?v1 S7) (?v2 S5) (implies (= (f6 ?v0 (f8 (f9 ?v1) f7)) f1) (implies (= (f6 ?v0 ?v2) f1) (= (f6 ?v0 (f8 (f9 ?v1) ?v2)) f1))) )
+:assumption (forall (?v0 S5) (?v1 S7) (?v2 S5) (implies (= (f6 ?v0 (f8 (f9 ?v1) ?v2)) f1) (and (= (f6 ?v0 (f8 (f9 ?v1) f7)) f1) (= (f6 ?v0 ?v2) f1))) )
+:assumption (forall (?v0 S5) (?v1 S4) (?v2 S10) (?v3 S4) (?v4 S4) (implies (= (f6 ?v0 (f8 (f9 (f10 (f11 (f12 f13 ?v1) ?v2) ?v3)) f7)) f1) (implies (forall (?v5 S2) (?v6 S2) (implies (= (f3 (f4 ?v3 ?v5) ?v6) f1) (= (f3 (f4 ?v4 ?v5) ?v6) f1))) (= (f6 ?v0 (f8 (f9 (f10 (f11 (f12 f13 ?v1) ?v2) ?v4)) f7)) f1))) )
+:assumption (forall (?v0 S5) (?v1 S4) (?v2 S10) (?v3 S4) (?v4 S4) (implies (= (f6 ?v0 (f8 (f9 (f10 (f11 (f12 f13 ?v1) ?v2) ?v3)) f7)) f1) (implies (forall (?v5 S2) (?v6 S2) (implies (= (f3 (f4 ?v4 ?v5) ?v6) f1) (= (f3 (f4 ?v1 ?v5) ?v6) f1))) (= (f6 ?v0 (f8 (f9 (f10 (f11 (f12 f13 ?v4) ?v2) ?v3)) f7)) f1))) )
+:formula true)
+; solver: z3
+; timeout: 5.0
+; random seed: 1
+; arguments:
+; DISPLAY_PROOF=true
+; PROOF_MODE=2
+; -rs:1
+; MODEL=true
+; -smt
diff --git a/test/regress/regress0/fmf/Makefile.am b/test/regress/regress0/fmf/Makefile.am
new file mode 100644
index 000000000..601d65799
--- /dev/null
+++ b/test/regress/regress0/fmf/Makefile.am
@@ -0,0 +1,52 @@
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
+LOG_COMPILER = @srcdir@/../../run_regression
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+
+if AUTOMAKE_1_11
+# old-style (pre-automake 1.12) test harness
+TESTS_ENVIRONMENT = \
+ $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(AM_LOG_FLAGS) $(LOG_FLAGS)
+endif
+
+MAKEFLAGS = -k
+
+# These are run for all build profiles.
+# If a test shouldn't be run in e.g. competition mode,
+# put it below in "TESTS +="
+TESTS = \
+ agree466.smt2 \
+ ALG008-1.smt2 \
+ german169.smt2 \
+ Hoare-z3.931718.smt \
+ QEpres-uf.855035.smt \
+ agree467.smt2 \
+ Arrow_Order-smtlib.778341.smt \
+ german73.smt2 \
+ PUZ001+1.smt2 \
+ refcount24.cvc.smt2 \
+ bug0909.smt2
+
+EXTRA_DIST = $(TESTS)
+
+#if CVC4_BUILD_PROFILE_COMPETITION
+#else
+#TESTS += \
+# error.cvc
+#endif
+#
+# and make sure to distribute it
+#EXTRA_DIST += \
+# error.cvc
+
+# synonyms for "check" in this directory
+.PHONY: regress regress0 test
+regress regress0 test: check
+
+# do nothing in this subdir
+.PHONY: regress1 regress2 regress3
+regress1 regress2 regress3:
diff --git a/test/regress/regress0/fmf/PUZ001+1.smt2 b/test/regress/regress0/fmf/PUZ001+1.smt2
new file mode 100644
index 000000000..4bcbf51c6
--- /dev/null
+++ b/test/regress/regress0/fmf/PUZ001+1.smt2
@@ -0,0 +1,119 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: unsat
+; EXIT: 20
+;%------------------------------------------------------------------------------
+;% File : PUZ001+1 : TPTP v5.4.0. Released v2.0.0.
+;% Domain : Puzzles
+;% Problem : Dreadbury Mansion
+;% Version : Especial.
+;% Theorem formulation : Reduced > Complete.
+;% English : Someone who lives in Dreadbury Mansion killed Aunt Agatha.
+;% Agatha, the butler, and Charles live in Dreadbury Mansion,
+;% and are the only people who live therein. A killer always
+;% hates his victim, and is never richer than his victim.
+;% Charles hates no one that Aunt Agatha hates. Agatha hates
+;% everyone except the butler. The butler hates everyone not
+;% richer than Aunt Agatha. The butler hates everyone Aunt
+;% Agatha hates. No one hates everyone. Agatha is not the
+;% butler. Therefore : Agatha killed herself.
+
+;% Refs : [Pel86] Pelletier (1986), Seventy-five Problems for Testing Au
+;% : [Hah94] Haehnle (1994), Email to G. Sutcliffe
+;% Source : [Hah94]
+;% Names : Pelletier 55 [Pel86]
+
+;% Status : Theorem
+;% Rating : 0.07 v5.3.0, 0.19 v5.2.0, 0.00 v5.0.0, 0.08 v4.1.0, 0.13 v4.0.0, 0.12 v3.7.0, 0.14 v3.5.0, 0.00 v3.4.0, 0.08 v3.3.0, 0.11 v3.2.0, 0.22 v3.1.0, 0.17 v2.7.0, 0.00 v2.5.0, 0.33 v2.4.0, 0.33 v2.2.1, 0.00 v2.1.0
+;% Syntax : Number of formulae : 14 ( 6 unit)
+;% Number of atoms : 24 ( 5 equality)
+;% Maximal formula depth : 5 ( 3 average)
+;% Number of connectives : 16 ( 6 ~; 2 |; 1 &)
+;% ( 0 <=>; 7 =>; 0 <=; 0 <~>)
+;% ( 0 ~|; 0 ~&)
+;% Number of predicates : 5 ( 0 propositional; 1-2 arity)
+;% Number of functors : 3 ( 3 constant; 0-0 arity)
+;% Number of variables : 12 ( 0 sgn; 10 !; 2 ?)
+;% Maximal term depth : 1 ( 1 average)
+;% SPC : FOF_THM_RFO_SEQ
+
+;% Comments : Modified by Geoff Sutcliffe.
+;% : Also known as "Who killed Aunt Agatha"
+;%------------------------------------------------------------------------------
+;%----Problem axioms
+(set-logic UF)
+(set-info :status unsat)
+(declare-sort sort__smt2 0)
+; functions
+(declare-fun agatha__smt2_0 ( ) sort__smt2)
+(declare-fun butler__smt2_0 ( ) sort__smt2)
+(declare-fun charles__smt2_0 ( ) sort__smt2)
+; predicates
+(declare-fun lives__smt2_1 ( sort__smt2 ) Bool)
+(declare-fun killed__smt2_2 ( sort__smt2 sort__smt2 ) Bool)
+(declare-fun hates__smt2_2 ( sort__smt2 sort__smt2 ) Bool)
+(declare-fun richer__smt2_2 ( sort__smt2 sort__smt2 ) Bool)
+
+; pel55_1 axiom
+(assert (exists ((?X sort__smt2))
+ (and (lives__smt2_1 ?X)
+ (killed__smt2_2 ?X agatha__smt2_0))))
+
+; pel55_2_1 axiom
+(assert (lives__smt2_1 agatha__smt2_0))
+
+; pel55_2_2 axiom
+(assert (lives__smt2_1 butler__smt2_0))
+
+; pel55_2_3 axiom
+(assert (lives__smt2_1 charles__smt2_0))
+
+; pel55_3 axiom
+(assert (forall ((?X sort__smt2))
+ (=> (lives__smt2_1 ?X)
+ (or (= ?X agatha__smt2_0)
+ (= ?X butler__smt2_0)
+ (= ?X charles__smt2_0)))))
+
+; pel55_4 axiom
+(assert (forall ((?X sort__smt2) (?Y sort__smt2))
+ (=> (killed__smt2_2 ?X ?Y)
+ (hates__smt2_2 ?X ?Y))))
+
+; pel55_5 axiom
+(assert (forall ((?X sort__smt2) (?Y sort__smt2))
+ (=> (killed__smt2_2 ?X ?Y)
+ (not (richer__smt2_2 ?X ?Y)))))
+
+; pel55_6 axiom
+(assert (forall ((?X sort__smt2))
+ (=> (hates__smt2_2 agatha__smt2_0 ?X)
+ (not (hates__smt2_2 charles__smt2_0 ?X)))))
+
+; pel55_7 axiom
+(assert (forall ((?X sort__smt2))
+ (=> (not (= ?X butler__smt2_0))
+ (hates__smt2_2 agatha__smt2_0 ?X))))
+
+; pel55_8 axiom
+(assert (forall ((?X sort__smt2))
+ (=> (not (richer__smt2_2 ?X agatha__smt2_0))
+ (hates__smt2_2 butler__smt2_0 ?X))))
+
+; pel55_9 axiom
+(assert (forall ((?X sort__smt2))
+ (=> (hates__smt2_2 agatha__smt2_0 ?X)
+ (hates__smt2_2 butler__smt2_0 ?X))))
+
+; pel55_10 axiom
+(assert (forall ((?X sort__smt2))
+(exists ((?Y sort__smt2)) (not (hates__smt2_2 ?X ?Y)))))
+
+; pel55_11 axiom
+(assert (not (= agatha__smt2_0 butler__smt2_0)))
+
+;----This is the conjecture with negated conjecture
+; pel55 conjecture
+(assert (not (killed__smt2_2 agatha__smt2_0 agatha__smt2_0)))
+
+
+(check-sat)
diff --git a/test/regress/regress0/fmf/QEpres-uf.855035.smt b/test/regress/regress0/fmf/QEpres-uf.855035.smt
new file mode 100644
index 000000000..95ab0cb34
--- /dev/null
+++ b/test/regress/regress0/fmf/QEpres-uf.855035.smt
@@ -0,0 +1,85 @@
+% COMMAND-LINE: --finite-model-find
+% EXPECT: sat
+% EXIT: 10
+(benchmark Isabelle
+:status sat
+:logic AUFLIA
+:extrasorts ( S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 S14 S15 S16 S17 S18)
+:extrafuns (
+ (f1 S1)
+ (f2 S1)
+ (f3 S2 S3 S4)
+ (f4 S2)
+ (f5 S3)
+ (f6 S4)
+ (f7 S3 S5 S1)
+ (f8 S6 S5)
+ (f9 S6)
+ (f10 S7 S6 S6)
+ (f11 S7)
+ (f12 S8 S4 S4)
+ (f13 S8)
+ (f14 S10 S3 S3)
+ (f15 S11 S9 S10)
+ (f16 S12 S4 S11)
+ (f17 S12)
+ (f18 S4 S13 S1)
+ (f19 S13)
+ (f20 S4 S1)
+ (f21 S2)
+ (f22 S10)
+ (f23 S3 S9 S1)
+ (f24 S14 S9 S9)
+ (f25 S15 S4 S14)
+ (f26 S15)
+ (f27 S13)
+ (f28 S8)
+ (f29 S16 S9 S3)
+ (f30 S17 S4 S16)
+ (f31 S18 S4 S17)
+ (f32 S18)
+ (f33 S18)
+ (f34 S4 S4 S1)
+)
+:assumption (not (= f1 f2))
+:assumption (not (not (= (f3 f4 f5) f6)))
+:assumption (forall (?v0 S3) (implies (= (f7 ?v0 (f8 f9)) f1) (not (= (f3 f4 ?v0) f6))) )
+:assumption (= (f7 f5 (f8 (f10 f11 f9))) f1)
+:assumption (forall (?v0 S4) (iff (= f6 ?v0) (= ?v0 f6)) )
+:assumption (= (f12 f13 f6) f6)
+:assumption (forall (?v0 S4) (iff (= f6 (f12 f13 ?v0)) (= ?v0 f6)) )
+:assumption (forall (?v0 S4) (iff (= (f12 f13 ?v0) f6) (= ?v0 f6)) )
+:assumption (forall (?v0 S4) (?v1 S9) (?v2 S3) (= (f3 f4 (f14 (f15 (f16 f17 ?v0) ?v1) ?v2)) (f3 f4 ?v2)) )
+:assumption (= (f18 f6 f19) f1)
+:assumption (= (f20 f6) f1)
+:assumption (forall (?v0 S4) (iff (= (f20 ?v0) f1) (= ?v0 f6)) )
+:assumption (forall (?v0 S3) (implies (= (f7 ?v0 (f8 f9)) f1) (not (= (f3 f21 ?v0) f6))) )
+:assumption (forall (?v0 S3) (implies (not (not (= (f3 f21 ?v0) f6))) (implies (not (= (f3 f4 ?v0) f6)) (not (= (f3 f4 (f14 f22 ?v0)) f6)))) )
+:assumption (forall (?v0 S4) (?v1 S4) (iff (= (f12 f13 ?v0) (f12 f13 ?v1)) (= ?v0 ?v1)) )
+:assumption (forall (?v0 S6) (?v1 S9) (implies (forall (?v2 S3) (implies (= (f7 ?v2 (f8 ?v0)) f1) (not (= (f3 f21 ?v2) f6)))) (iff (exists (?v2 S4) (forall (?v3 S3) (implies (= (f7 ?v3 (f8 (f10 f11 ?v0))) f1) (= (f23 ?v3 (f24 (f25 f26 ?v2) ?v1)) f1)))) (exists (?v2 S4) (forall (?v3 S3) (implies (= (f7 ?v3 (f8 ?v0)) f1) (= (f23 ?v3 (f24 (f25 f26 ?v2) ?v1)) f1)))))) )
+:assumption (forall (?v0 S4) (= (f18 (f12 f13 ?v0) f27) f1) )
+:assumption (= (f12 f28 f6) f6)
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S9) (= (f3 f4 (f29 (f30 (f31 f32 ?v0) ?v1) ?v2)) ?v0) )
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S9) (= (f3 f4 (f29 (f30 (f31 f33 ?v0) ?v1) ?v2)) ?v0) )
+:assumption (= (f18 f6 f27) f1)
+:assumption (forall (?v0 S3) (?v1 S4) (?v2 S9) (implies (not (not (= (f3 f21 ?v0) f6))) (iff (= (f23 ?v0 (f24 (f25 f26 ?v1) ?v2)) f1) (= (f23 (f14 f22 ?v0) ?v2) f1))) )
+:assumption (forall (?v0 S4) (iff (= (f34 (f12 f13 ?v0) f6) f1) (= (f34 ?v0 f6) f1)) )
+:assumption (forall (?v0 S4) (iff (= (f34 f6 (f12 f13 ?v0)) f1) (= (f34 f6 ?v0) f1)) )
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S9) (?v3 S4) (?v4 S4) (?v5 S9) (not (= (f29 (f30 (f31 f33 ?v0) ?v1) ?v2) (f29 (f30 (f31 f32 ?v3) ?v4) ?v5))) )
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S9) (?v3 S4) (?v4 S4) (?v5 S9) (not (= (f29 (f30 (f31 f32 ?v0) ?v1) ?v2) (f29 (f30 (f31 f33 ?v3) ?v4) ?v5))) )
+:assumption (forall (?v0 S4) (= (f34 ?v0 ?v0) f1) )
+:assumption (forall (?v0 S4) (?v1 S4) (or (= (f34 ?v0 ?v1) f1) (= (f34 ?v1 ?v0) f1)) )
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S9) (?v3 S4) (?v4 S4) (?v5 S9) (iff (= (f29 (f30 (f31 f33 ?v0) ?v1) ?v2) (f29 (f30 (f31 f33 ?v3) ?v4) ?v5)) (and (= ?v0 ?v3) (and (= ?v1 ?v4) (= ?v2 ?v5)))) )
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S9) (?v3 S4) (?v4 S4) (?v5 S9) (iff (= (f29 (f30 (f31 f32 ?v0) ?v1) ?v2) (f29 (f30 (f31 f32 ?v3) ?v4) ?v5)) (and (= ?v0 ?v3) (and (= ?v1 ?v4) (= ?v2 ?v5)))) )
+:assumption (forall (?v0 S4) (?v1 S4) (?v2 S4) (implies (= (f34 ?v0 ?v1) f1) (implies (= (f34 ?v1 ?v2) f1) (= (f34 ?v0 ?v2) f1))) )
+:assumption (forall (?v0 S4) (?v1 S4) (implies (= (f34 ?v0 ?v1) f1) (implies (= (f34 ?v1 ?v0) f1) (= ?v0 ?v1))) )
+:formula true)
+; solver: z3
+; timeout: 1.897
+; random seed: 1
+; arguments:
+; DISPLAY_PROOF=true
+; PROOF_MODE=2
+; -rs:1
+; MODEL=true
+; -smt
diff --git a/test/regress/regress0/fmf/agree466.smt2 b/test/regress/regress0/fmf/agree466.smt2
new file mode 100644
index 000000000..2a021ea9b
--- /dev/null
+++ b/test/regress/regress0/fmf/agree466.smt2
@@ -0,0 +1,475 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: sat
+; EXIT: 10
+; Preamble --------------
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(declare-datatypes () ((UNIT (Unit))))
+(declare-datatypes () ((BOOL (Truth) (Falsity))))
+
+; Decls --------------
+(declare-sort node$type 0)
+(declare-sort value$type 0)
+(define-sort Nodes$elem$type () node$type)
+(declare-sort Nodes$t$type 0)
+(declare-fun Nodes$empty () Nodes$t$type)
+(declare-fun Nodes$mem (Nodes$elem$type Nodes$t$type) BOOL)
+(declare-fun Nodes$add (Nodes$elem$type Nodes$t$type) Nodes$t$type)
+(declare-fun Nodes$remove (Nodes$elem$type Nodes$t$type) Nodes$t$type)
+(declare-fun Nodes$cardinality (Nodes$t$type) Int)
+(declare-fun Nodes$union (Nodes$t$type Nodes$t$type) Nodes$t$type)
+(declare-fun Nodes$disjoint (Nodes$t$type Nodes$t$type) BOOL)
+;Nodes$disjoint_empty :
+(assert (forall ((a Nodes$t$type)) (= (Nodes$disjoint a Nodes$empty) Truth)))
+;Nodes$disjoint_comm :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (= (Nodes$disjoint a b)
+ (Nodes$disjoint b a))))
+;Nodes$mem_empty :
+(assert (forall ((e Nodes$elem$type)) (not (= (Nodes$mem e Nodes$empty)
+ Truth))))
+;Nodes$mem_add :
+(assert (forall ((x Nodes$elem$type) (y Nodes$elem$type) (s Nodes$t$type))
+ (= (Nodes$mem x (Nodes$add y s)) (ite (or (= x y) (= (Nodes$mem x s)
+ Truth)) Truth
+ Falsity))))
+;Nodes$mem_remove :
+(assert (forall ((x Nodes$elem$type) (y Nodes$elem$type) (s Nodes$t$type))
+ (= (Nodes$mem x (Nodes$remove y s)) (ite (and (not (= x y)) (=
+ (Nodes$mem
+ x s)
+ Truth))
+ Truth Falsity))))
+;Nodes$mem_union1 :
+(assert (forall ((x Nodes$elem$type) (a Nodes$t$type)) (=> (= (Nodes$mem x a)
+ Truth) (forall
+ ((b Nodes$t$type))
+ (=
+ (Nodes$mem
+ x (Nodes$union
+ a b))
+ Truth)))))
+;Nodes$mem_union2 :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (= (Nodes$union a b)
+ (Nodes$union b a))))
+;Nodes$mem_union3 :
+(assert (forall ((x Nodes$elem$type) (a Nodes$t$type) (b Nodes$t$type))
+ (=> (= (Nodes$mem x (Nodes$union a b)) Truth) (or (= (Nodes$mem x a)
+ Truth) (= (Nodes$mem
+ x b)
+ Truth)))))
+;Nodes$mem_union4 :
+(assert (forall ((a Nodes$t$type)) (= (Nodes$union a a) a)))
+;Nodes$mem_union5 :
+(assert (forall ((a Nodes$t$type)) (= (Nodes$union a Nodes$empty) a)))
+;Nodes$empty_union :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (=> (= (Nodes$union a b)
+ Nodes$empty)
+ (= a Nodes$empty))))
+;Nodes$card_empty :
+(assert (= (Nodes$cardinality Nodes$empty) 0))
+;Nodes$card_zero :
+(assert (forall ((s Nodes$t$type)) (=> (= (Nodes$cardinality s) 0) (=
+ s
+ Nodes$empty))))
+;Nodes$card_non_negative :
+(assert (forall ((s Nodes$t$type)) (>= (Nodes$cardinality s) 0)))
+;Nodes$card_add :
+(assert (forall ((x Nodes$elem$type) (s Nodes$t$type)) (= (Nodes$cardinality
+ (Nodes$add x s))
+ (ite (= (Nodes$mem
+ x s) Truth)
+ (Nodes$cardinality
+ s) (+ (Nodes$cardinality
+ s) 1)))))
+;Nodes$card_remove :
+(assert (forall ((x Nodes$elem$type) (s Nodes$t$type)) (= (Nodes$cardinality
+ (Nodes$remove x s))
+ (ite (= (Nodes$mem
+ x s) Truth) (-
+ (Nodes$cardinality
+ s) 1) (Nodes$cardinality
+ s)))))
+;Nodes$card_union :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (=> (= (Nodes$disjoint
+ a b) Truth)
+ (= (Nodes$cardinality
+ (Nodes$union a b)) (+
+ (Nodes$cardinality
+ a) (Nodes$cardinality b))))))
+(declare-fun Nodes$eq (Nodes$t$type Nodes$t$type) BOOL)
+;Nodes$eq_is_equality :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (= (Nodes$eq a b)
+ (ite (= a b) Truth
+ Falsity))))
+;Nodes$equal1 :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (=> (forall ((x Nodes$elem$type))
+ (= (Nodes$mem x a)
+ (Nodes$mem x b)))
+ (= (Nodes$eq a b)
+ Truth))))
+(define-sort Values$elem$type () value$type)
+(declare-sort Values$t$type 0)
+(declare-fun Values$empty () Values$t$type)
+(declare-fun Values$mem (Values$elem$type Values$t$type) BOOL)
+(declare-fun Values$add (Values$elem$type Values$t$type) Values$t$type)
+(declare-fun Values$remove (Values$elem$type Values$t$type) Values$t$type)
+(declare-fun Values$cardinality (Values$t$type) Int)
+(declare-fun Values$union (Values$t$type Values$t$type) Values$t$type)
+(declare-fun Values$disjoint (Values$t$type Values$t$type) BOOL)
+;Values$disjoint_empty :
+(assert (forall ((a Values$t$type)) (= (Values$disjoint a Values$empty)
+ Truth)))
+;Values$disjoint_comm :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (= (Values$disjoint
+ a b) (Values$disjoint
+ b a))))
+;Values$mem_empty :
+(assert (forall ((e Values$elem$type)) (not (= (Values$mem e Values$empty)
+ Truth))))
+;Values$mem_add :
+(assert (forall ((x Values$elem$type) (y Values$elem$type) (s Values$t$type))
+ (= (Values$mem x (Values$add y s)) (ite (or (= x y) (= (Values$mem
+ x s) Truth))
+ Truth Falsity))))
+;Values$mem_remove :
+(assert (forall ((x Values$elem$type) (y Values$elem$type) (s Values$t$type))
+ (= (Values$mem x (Values$remove y s)) (ite (and (not (= x y))
+ (= (Values$mem x s)
+ Truth)) Truth Falsity))))
+;Values$mem_union1 :
+(assert (forall ((x Values$elem$type) (a Values$t$type)) (=> (= (Values$mem
+ x a)
+ Truth) (forall
+ (
+ (b Values$t$type))
+ (=
+ (Values$mem
+ x
+ (Values$union
+ a b))
+ Truth)))))
+;Values$mem_union2 :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (= (Values$union a b)
+ (Values$union b a))))
+;Values$mem_union3 :
+(assert (forall ((x Values$elem$type) (a Values$t$type) (b Values$t$type))
+ (=> (= (Values$mem x (Values$union a b)) Truth) (or (= (Values$mem
+ x a) Truth)
+ (= (Values$mem x b)
+ Truth)))))
+;Values$mem_union4 :
+(assert (forall ((a Values$t$type)) (= (Values$union a a) a)))
+;Values$mem_union5 :
+(assert (forall ((a Values$t$type)) (= (Values$union a Values$empty) a)))
+;Values$empty_union :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (=> (= (Values$union
+ a b) Values$empty)
+ (= a Values$empty))))
+;Values$card_empty :
+(assert (= (Values$cardinality Values$empty) 0))
+;Values$card_zero :
+(assert (forall ((s Values$t$type)) (=> (= (Values$cardinality s) 0)
+ (= s Values$empty))))
+;Values$card_non_negative :
+(assert (forall ((s Values$t$type)) (>= (Values$cardinality s) 0)))
+;Values$card_add :
+(assert (forall ((x Values$elem$type) (s Values$t$type)) (= (Values$cardinality
+ (Values$add x s))
+ (ite (= (Values$mem
+ x s)
+ Truth)
+ (Values$cardinality
+ s) (+ (Values$cardinality
+ s) 1)))))
+;Values$card_remove :
+(assert (forall ((x Values$elem$type) (s Values$t$type)) (= (Values$cardinality
+ (Values$remove
+ x s)) (ite
+ (=
+ (Values$mem
+ x s)
+ Truth) (-
+ (Values$cardinality
+ s)
+ 1)
+ (Values$cardinality
+ s)))))
+;Values$card_union :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (=> (= (Values$disjoint
+ a b) Truth)
+ (= (Values$cardinality
+ (Values$union a b)) (+
+ (Values$cardinality
+ a) (Values$cardinality
+ b))))))
+(declare-fun Values$eq (Values$t$type Values$t$type) BOOL)
+;Values$eq_is_equality :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (= (Values$eq a b)
+ (ite (= a b) Truth
+ Falsity))))
+;Values$equal1 :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (=> (forall ((x Values$elem$type))
+ (= (Values$mem x a)
+ (Values$mem
+ x b))) (= (Values$eq
+ a b)
+ Truth))))
+(define-sort node_set$type () (Array node$type BOOL))
+(declare-fun mk_array_1 () (Array node$type BOOL))
+;mk_array_1_def :
+(assert (forall ((mk_array_1_index node$type)) (= (select mk_array_1
+ mk_array_1_index) Falsity)))
+(define-fun empty_node_set () node_set$type mk_array_1)
+(define-sort node_pair_set$type () (Array node$type (Array node$type BOOL)))
+(declare-fun mk_array_2 () (Array node$type BOOL))
+;mk_array_2_def :
+(assert (forall ((mk_array_2_index node$type)) (= (select mk_array_2
+ mk_array_2_index) Falsity)))
+(declare-fun mk_array_3 () (Array node$type (Array node$type BOOL)))
+;mk_array_3_def :
+(assert (forall ((mk_array_3_index node$type)) (= (select mk_array_3
+ mk_array_3_index) mk_array_2)))
+(define-fun empty_node_pair_set () node_pair_set$type mk_array_3)
+(declare-fun mk_array_4 () (Array node$type BOOL))
+;mk_array_4_def :
+(assert (forall ((mk_array_4_index node$type)) (= (select mk_array_4
+ mk_array_4_index) Truth)))
+(declare-fun mk_array_5 () (Array node$type (Array node$type BOOL)))
+;mk_array_5_def :
+(assert (forall ((mk_array_5_index node$type)) (= (select mk_array_5
+ mk_array_5_index) mk_array_4)))
+(define-fun full_node_pair_set () node_pair_set$type mk_array_5)
+(declare-fun input () (Array node$type value$type))
+(declare-fun t () Int)
+;positive_bound :
+(assert (> t 0))
+(define-sort message$type () Values$t$type)
+(define-sort message_set$type () (Array node$type message$type))
+(define-sort state$type () Values$t$type)
+(define-sort state_set$type () (Array node$type state$type))
+(define-fun null_message () message$type Values$empty)
+(declare-fun mk_array_6 () (Array node$type message$type))
+;mk_array_6_def :
+(assert (forall ((mk_array_6_index node$type)) (= (select mk_array_6
+ mk_array_6_index) null_message)))
+(define-fun null_message_set () message_set$type mk_array_6)
+(define-fun null_state () state$type Values$empty)
+(declare-fun mk_array_7 () (Array node$type state$type))
+;mk_array_7_def :
+(assert (forall ((mk_array_7_index node$type)) (= (select mk_array_7
+ mk_array_7_index) null_state)))
+(define-fun null_state_set () state_set$type mk_array_7)
+(declare-fun choose (Values$t$type) value$type)
+;choosen_value :
+(assert (forall ((vals Values$t$type)) (or (= vals Values$empty) (= (Values$mem
+ (choose
+ vals)
+ vals)
+ Truth))))
+(define-sort failure_pattern$type () node_pair_set$type)
+(define-fun is_faulty ((p node$type) (deliver failure_pattern$type)) BOOL
+(ite (exists ((q node$type)) (not (= (select (select deliver p) q) Truth)))
+Truth Falsity))
+(define-fun is_silent ((p node$type) (deliver failure_pattern$type)) BOOL
+(ite (forall ((q node$type)) (not (= (select (select deliver p) q) Truth)))
+Truth Falsity))
+(declare-datatypes () ((phase_state$type (init_phase) (send_phase) (recv_phase) (comp_phase))))
+(declare-datatypes () ((clean_state$type (before) (active) (after))))
+
+; Var Decls --------------
+(declare-fun my_compute$result$1 () state$type)
+(declare-fun output$1 () (Array node$type value$type))
+(declare-fun comp_done () node_set$type)
+(declare-fun compute$can_decide$0$1 () BOOL)
+(declare-fun chosen () (Array node$type BOOL))
+(declare-fun recv_done () node_pair_set$type)
+(declare-fun output () (Array node$type value$type))
+(declare-fun phase () phase_state$type)
+(declare-fun global_state () state_set$type)
+(declare-fun my_decide$result$1 () value$type)
+(declare-fun round () Int)
+(declare-fun compute$n () node$type)
+(declare-fun send_done () node_pair_set$type)
+(declare-fun my_can_decide$result$1 () BOOL)
+(declare-fun chosen$1 () (Array node$type BOOL))
+(declare-fun comp_done$1 () node_set$type)
+(declare-fun global_state$1 () state_set$type)
+
+; Asserts --------------
+(assert (not (=> (forall ((n node$type)) (=>
+ (and
+ (=
+ (select
+ chosen
+ n)
+ Truth)
+ (=
+ round (+
+ t
+ 1)))
+ (and
+ (forall
+ (
+ (n node$type) (m node$type))
+ (=
+ (select
+ (select
+ send_done
+ n)
+ m)
+ Truth))
+ (forall
+ (
+ (n node$type) (m node$type))
+ (=
+ (select
+ (select
+ recv_done
+ n)
+ m)
+ Truth)))))
+ (=> (= phase comp_phase) (=>
+ (not
+ (= (select
+ comp_done
+ compute$n)
+ Truth))
+ (=>
+ (= my_compute$result$1
+ (select
+ global_state
+ compute$n))
+ (=>
+ (= global_state$1
+ (store
+ global_state
+ compute$n
+ my_compute$result$1))
+ (=>
+ (= my_can_decide$result$1
+ (ite
+ (= round (+
+ t 1))
+ Truth
+ Falsity))
+ (=>
+ (= compute$can_decide$0$1
+ my_can_decide$result$1)
+ (= (ite
+ (=
+ compute$can_decide$0$1
+ Truth)
+ (ite
+ (=>
+ (=
+ my_decide$result$1
+ (choose
+ (select
+ global_state$1
+ compute$n)))
+ (=>
+ (=
+ output$1
+ (store
+ output
+ compute$n
+ my_decide$result$1))
+ (=>
+ (=
+ chosen$1
+ (store
+ chosen
+ compute$n
+ Truth))
+ (=>
+ (=
+ comp_done$1
+ (store
+ comp_done
+ compute$n
+ Truth))
+ (forall
+ (
+ (n node$type))
+ (=>
+ (and
+ (=
+ (select
+ chosen$1
+ n)
+ Truth)
+ (=
+ round (+
+ t
+ 1)))
+ (and
+ (forall
+ (
+ (n node$type) (m node$type))
+ (=
+ (select
+ (select
+ send_done
+ n)
+ m)
+ Truth))
+ (forall
+ (
+ (n node$type) (m node$type))
+ (=
+ (select
+ (select
+ recv_done
+ n)
+ m)
+ Truth)))))))))
+ Truth
+ Falsity)
+ (ite
+ (=>
+ (=
+ comp_done$1
+ (store
+ comp_done
+ compute$n
+ Truth))
+ (forall
+ (
+ (n node$type))
+ (=>
+ (and
+ (=
+ (select
+ chosen
+ n)
+ Truth)
+ (=
+ round (+
+ t
+ 1)))
+ (and
+ (forall
+ (
+ (n node$type) (m node$type))
+ (=
+ (select
+ (select
+ send_done
+ n)
+ m)
+ Truth))
+ (forall
+ (
+ (n node$type) (m node$type))
+ (=
+ (select
+ (select
+ recv_done
+ n)
+ m)
+ Truth))))))
+ Truth
+ Falsity))
+ Truth))))))))))
+
+(check-sat)
diff --git a/test/regress/regress0/fmf/agree467.smt2 b/test/regress/regress0/fmf/agree467.smt2
new file mode 100644
index 000000000..09e16dfe3
--- /dev/null
+++ b/test/regress/regress0/fmf/agree467.smt2
@@ -0,0 +1,342 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: unsat
+; EXIT: 20
+; Preamble --------------
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+(declare-datatypes () ((UNIT (Unit))))
+(declare-datatypes () ((BOOL (Truth) (Falsity))))
+
+; Decls --------------
+(declare-sort node$type 0)
+(declare-sort value$type 0)
+(define-sort Nodes$elem$type () node$type)
+(declare-sort Nodes$t$type 0)
+(declare-fun Nodes$empty () Nodes$t$type)
+(declare-fun Nodes$mem (Nodes$elem$type Nodes$t$type) BOOL)
+(declare-fun Nodes$add (Nodes$elem$type Nodes$t$type) Nodes$t$type)
+(declare-fun Nodes$remove (Nodes$elem$type Nodes$t$type) Nodes$t$type)
+(declare-fun Nodes$cardinality (Nodes$t$type) Int)
+(declare-fun Nodes$union (Nodes$t$type Nodes$t$type) Nodes$t$type)
+(declare-fun Nodes$disjoint (Nodes$t$type Nodes$t$type) BOOL)
+;Nodes$disjoint_empty :
+(assert (forall ((a Nodes$t$type)) (= (Nodes$disjoint a Nodes$empty) Truth)))
+;Nodes$disjoint_comm :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (= (Nodes$disjoint a b)
+ (Nodes$disjoint b a))))
+;Nodes$mem_empty :
+(assert (forall ((e Nodes$elem$type)) (not (= (Nodes$mem e Nodes$empty)
+ Truth))))
+;Nodes$mem_add :
+(assert (forall ((x Nodes$elem$type) (y Nodes$elem$type) (s Nodes$t$type))
+ (= (Nodes$mem x (Nodes$add y s)) (ite (or (= x y) (= (Nodes$mem x s)
+ Truth)) Truth
+ Falsity))))
+;Nodes$mem_remove :
+(assert (forall ((x Nodes$elem$type) (y Nodes$elem$type) (s Nodes$t$type))
+ (= (Nodes$mem x (Nodes$remove y s)) (ite (and (not (= x y)) (=
+ (Nodes$mem
+ x s)
+ Truth))
+ Truth Falsity))))
+;Nodes$mem_union1 :
+(assert (forall ((x Nodes$elem$type) (a Nodes$t$type)) (=> (= (Nodes$mem x a)
+ Truth) (forall
+ ((b Nodes$t$type))
+ (=
+ (Nodes$mem
+ x (Nodes$union
+ a b))
+ Truth)))))
+;Nodes$mem_union2 :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (= (Nodes$union a b)
+ (Nodes$union b a))))
+;Nodes$mem_union3 :
+(assert (forall ((x Nodes$elem$type) (a Nodes$t$type) (b Nodes$t$type))
+ (=> (= (Nodes$mem x (Nodes$union a b)) Truth) (or (= (Nodes$mem x a)
+ Truth) (= (Nodes$mem
+ x b)
+ Truth)))))
+;Nodes$mem_union4 :
+(assert (forall ((a Nodes$t$type)) (= (Nodes$union a a) a)))
+;Nodes$mem_union5 :
+(assert (forall ((a Nodes$t$type)) (= (Nodes$union a Nodes$empty) a)))
+;Nodes$empty_union :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (=> (= (Nodes$union a b)
+ Nodes$empty)
+ (= a Nodes$empty))))
+;Nodes$card_empty :
+(assert (= (Nodes$cardinality Nodes$empty) 0))
+;Nodes$card_zero :
+(assert (forall ((s Nodes$t$type)) (=> (= (Nodes$cardinality s) 0) (=
+ s
+ Nodes$empty))))
+;Nodes$card_non_negative :
+(assert (forall ((s Nodes$t$type)) (>= (Nodes$cardinality s) 0)))
+;Nodes$card_add :
+(assert (forall ((x Nodes$elem$type) (s Nodes$t$type)) (= (Nodes$cardinality
+ (Nodes$add x s))
+ (ite (= (Nodes$mem
+ x s) Truth)
+ (Nodes$cardinality
+ s) (+ (Nodes$cardinality
+ s) 1)))))
+;Nodes$card_remove :
+(assert (forall ((x Nodes$elem$type) (s Nodes$t$type)) (= (Nodes$cardinality
+ (Nodes$remove x s))
+ (ite (= (Nodes$mem
+ x s) Truth) (-
+ (Nodes$cardinality
+ s) 1) (Nodes$cardinality
+ s)))))
+;Nodes$card_union :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (=> (= (Nodes$disjoint
+ a b) Truth)
+ (= (Nodes$cardinality
+ (Nodes$union a b)) (+
+ (Nodes$cardinality
+ a) (Nodes$cardinality b))))))
+(declare-fun Nodes$eq (Nodes$t$type Nodes$t$type) BOOL)
+;Nodes$eq_is_equality :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (= (Nodes$eq a b)
+ (ite (= a b) Truth
+ Falsity))))
+;Nodes$equal1 :
+(assert (forall ((a Nodes$t$type) (b Nodes$t$type)) (=> (forall ((x Nodes$elem$type))
+ (= (Nodes$mem x a)
+ (Nodes$mem x b)))
+ (= (Nodes$eq a b)
+ Truth))))
+(define-sort Values$elem$type () value$type)
+(declare-sort Values$t$type 0)
+(declare-fun Values$empty () Values$t$type)
+(declare-fun Values$mem (Values$elem$type Values$t$type) BOOL)
+(declare-fun Values$add (Values$elem$type Values$t$type) Values$t$type)
+(declare-fun Values$remove (Values$elem$type Values$t$type) Values$t$type)
+(declare-fun Values$cardinality (Values$t$type) Int)
+(declare-fun Values$union (Values$t$type Values$t$type) Values$t$type)
+(declare-fun Values$disjoint (Values$t$type Values$t$type) BOOL)
+;Values$disjoint_empty :
+(assert (forall ((a Values$t$type)) (= (Values$disjoint a Values$empty)
+ Truth)))
+;Values$disjoint_comm :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (= (Values$disjoint
+ a b) (Values$disjoint
+ b a))))
+;Values$mem_empty :
+(assert (forall ((e Values$elem$type)) (not (= (Values$mem e Values$empty)
+ Truth))))
+;Values$mem_add :
+(assert (forall ((x Values$elem$type) (y Values$elem$type) (s Values$t$type))
+ (= (Values$mem x (Values$add y s)) (ite (or (= x y) (= (Values$mem
+ x s) Truth))
+ Truth Falsity))))
+;Values$mem_remove :
+(assert (forall ((x Values$elem$type) (y Values$elem$type) (s Values$t$type))
+ (= (Values$mem x (Values$remove y s)) (ite (and (not (= x y))
+ (= (Values$mem x s)
+ Truth)) Truth Falsity))))
+;Values$mem_union1 :
+(assert (forall ((x Values$elem$type) (a Values$t$type)) (=> (= (Values$mem
+ x a)
+ Truth) (forall
+ (
+ (b Values$t$type))
+ (=
+ (Values$mem
+ x
+ (Values$union
+ a b))
+ Truth)))))
+;Values$mem_union2 :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (= (Values$union a b)
+ (Values$union b a))))
+;Values$mem_union3 :
+(assert (forall ((x Values$elem$type) (a Values$t$type) (b Values$t$type))
+ (=> (= (Values$mem x (Values$union a b)) Truth) (or (= (Values$mem
+ x a) Truth)
+ (= (Values$mem x b)
+ Truth)))))
+;Values$mem_union4 :
+(assert (forall ((a Values$t$type)) (= (Values$union a a) a)))
+;Values$mem_union5 :
+(assert (forall ((a Values$t$type)) (= (Values$union a Values$empty) a)))
+;Values$empty_union :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (=> (= (Values$union
+ a b) Values$empty)
+ (= a Values$empty))))
+;Values$card_empty :
+(assert (= (Values$cardinality Values$empty) 0))
+;Values$card_zero :
+(assert (forall ((s Values$t$type)) (=> (= (Values$cardinality s) 0)
+ (= s Values$empty))))
+;Values$card_non_negative :
+(assert (forall ((s Values$t$type)) (>= (Values$cardinality s) 0)))
+;Values$card_add :
+(assert (forall ((x Values$elem$type) (s Values$t$type)) (= (Values$cardinality
+ (Values$add x s))
+ (ite (= (Values$mem
+ x s)
+ Truth)
+ (Values$cardinality
+ s) (+ (Values$cardinality
+ s) 1)))))
+;Values$card_remove :
+(assert (forall ((x Values$elem$type) (s Values$t$type)) (= (Values$cardinality
+ (Values$remove
+ x s)) (ite
+ (=
+ (Values$mem
+ x s)
+ Truth) (-
+ (Values$cardinality
+ s)
+ 1)
+ (Values$cardinality
+ s)))))
+;Values$card_union :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (=> (= (Values$disjoint
+ a b) Truth)
+ (= (Values$cardinality
+ (Values$union a b)) (+
+ (Values$cardinality
+ a) (Values$cardinality
+ b))))))
+(declare-fun Values$eq (Values$t$type Values$t$type) BOOL)
+;Values$eq_is_equality :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (= (Values$eq a b)
+ (ite (= a b) Truth
+ Falsity))))
+;Values$equal1 :
+(assert (forall ((a Values$t$type) (b Values$t$type)) (=> (forall ((x Values$elem$type))
+ (= (Values$mem x a)
+ (Values$mem
+ x b))) (= (Values$eq
+ a b)
+ Truth))))
+(define-sort node_set$type () (Array node$type BOOL))
+(declare-fun mk_array_1 () (Array node$type BOOL))
+;mk_array_1_def :
+(assert (forall ((mk_array_1_index node$type)) (= (select mk_array_1
+ mk_array_1_index) Falsity)))
+(define-fun empty_node_set () node_set$type mk_array_1)
+(define-sort node_pair_set$type () (Array node$type (Array node$type BOOL)))
+(declare-fun mk_array_2 () (Array node$type BOOL))
+;mk_array_2_def :
+(assert (forall ((mk_array_2_index node$type)) (= (select mk_array_2
+ mk_array_2_index) Falsity)))
+(declare-fun mk_array_3 () (Array node$type (Array node$type BOOL)))
+;mk_array_3_def :
+(assert (forall ((mk_array_3_index node$type)) (= (select mk_array_3
+ mk_array_3_index) mk_array_2)))
+(define-fun empty_node_pair_set () node_pair_set$type mk_array_3)
+(declare-fun mk_array_4 () (Array node$type BOOL))
+;mk_array_4_def :
+(assert (forall ((mk_array_4_index node$type)) (= (select mk_array_4
+ mk_array_4_index) Truth)))
+(declare-fun mk_array_5 () (Array node$type (Array node$type BOOL)))
+;mk_array_5_def :
+(assert (forall ((mk_array_5_index node$type)) (= (select mk_array_5
+ mk_array_5_index) mk_array_4)))
+(define-fun full_node_pair_set () node_pair_set$type mk_array_5)
+(declare-fun input () (Array node$type value$type))
+(declare-fun t () Int)
+;positive_bound :
+(assert (> t 0))
+(define-sort message$type () Values$t$type)
+(define-sort message_set$type () (Array node$type message$type))
+(define-sort state$type () Values$t$type)
+(define-sort state_set$type () (Array node$type state$type))
+(define-fun null_message () message$type Values$empty)
+(declare-fun mk_array_6 () (Array node$type message$type))
+;mk_array_6_def :
+(assert (forall ((mk_array_6_index node$type)) (= (select mk_array_6
+ mk_array_6_index) null_message)))
+(define-fun null_message_set () message_set$type mk_array_6)
+(define-fun null_state () state$type Values$empty)
+(declare-fun mk_array_7 () (Array node$type state$type))
+;mk_array_7_def :
+(assert (forall ((mk_array_7_index node$type)) (= (select mk_array_7
+ mk_array_7_index) null_state)))
+(define-fun null_state_set () state_set$type mk_array_7)
+(declare-fun choose (Values$t$type) value$type)
+;choosen_value :
+(assert (forall ((vals Values$t$type)) (or (= vals Values$empty) (= (Values$mem
+ (choose
+ vals)
+ vals)
+ Truth))))
+(define-sort failure_pattern$type () node_pair_set$type)
+(define-fun is_faulty ((p node$type) (deliver failure_pattern$type)) BOOL
+(ite (exists ((q node$type)) (not (= (select (select deliver p) q) Truth)))
+Truth Falsity))
+(define-fun is_silent ((p node$type) (deliver failure_pattern$type)) BOOL
+(ite (forall ((q node$type)) (not (= (select (select deliver p) q) Truth)))
+Truth Falsity))
+(declare-datatypes () ((phase_state$type (init_phase) (send_phase) (recv_phase) (comp_phase))))
+(declare-datatypes () ((clean_state$type (before) (active) (after))))
+
+; Var Decls --------------
+(declare-fun init_done () node_set$type)
+(declare-fun crashed () Nodes$t$type)
+(declare-fun comp_done () node_set$type)
+(declare-fun chosen () (Array node$type BOOL))
+(declare-fun recv_done () node_pair_set$type)
+(declare-fun phase () phase_state$type)
+(declare-fun clean () clean_state$type)
+(declare-fun global_state () state_set$type)
+(declare-fun messages () (Array node$type message_set$type))
+(declare-fun deliver_message () failure_pattern$type)
+(declare-fun crashing () Nodes$t$type)
+(declare-fun round () Int)
+(declare-fun send_done () node_pair_set$type)
+
+; Asserts --------------
+(declare-fun mk_array_8 () (Array node$type BOOL))
+;mk_array_8_def :
+(assert (forall ((mk_array_8_index node$type)) (= (select mk_array_8
+ mk_array_8_index) Falsity)))
+(declare-fun mk_array_9 () (Array node$type message_set$type))
+;mk_array_9_def :
+(assert (forall ((mk_array_9_index node$type)) (= (select mk_array_9
+ mk_array_9_index) null_message_set)))
+(assert (not (=> (and (and (and (and (and (and (and (and (and (and (and
+ (and
+ (=
+ clean
+ before)
+ (=
+ global_state
+ null_state_set))
+ (=
+ messages
+ mk_array_9))
+ (= deliver_message
+ full_node_pair_set))
+ (= comp_done
+ empty_node_set))
+ (= recv_done empty_node_pair_set))
+ (= send_done empty_node_pair_set))
+ (= init_done empty_node_set))
+ (= phase init_phase)) (= crashing
+ Nodes$empty))
+ (= crashed Nodes$empty)) (= round 0)) (= chosen
+ mk_array_8))
+ (forall ((n node$type)) (=> (and (= (select chosen n) Truth)
+ (= round (+ t 1))) (and (forall
+ ((n node$type) (m node$type))
+ (= (select
+ (select
+ send_done
+ n)
+ m)
+ Truth))
+ (forall (
+ (n node$type) (m node$type))
+ (= (select
+ (select
+ recv_done
+ n) m)
+ Truth))))))))
+
+(check-sat)
diff --git a/test/regress/regress0/fmf/bug0909.smt2 b/test/regress/regress0/fmf/bug0909.smt2
new file mode 100755
index 000000000..39862b8d6
--- /dev/null
+++ b/test/regress/regress0/fmf/bug0909.smt2
@@ -0,0 +1,55 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: unsat
+; EXIT: 20
+; Preamble --------------
+(set-option :produce-models true)
+(set-logic ALL_SUPPORTED)
+;(declare-datatypes () ((x2 (x1))))
+(declare-datatypes () ((x5 (x3) (x4))))
+(declare-sort x6 0)
+(declare-fun x7 (x6) x5)
+(declare-fun x8 () x6)
+(assert (not (= x3 (x7 x8))))
+(declare-fun x9 () x6)
+(assert (not (= x3 (x7 x9))))
+(declare-fun x11 () Int)
+(declare-sort x12 0)
+(declare-fun x13 () x12)
+(declare-datatypes () ((x17 (x14) (x15) (x16))))
+(declare-datatypes () ((x22 (x21 (x18 Int) (x19 Int) (x20 x5)))))
+(declare-datatypes () ((x29 (x28 (x23 x5) (x24 x5) (x25 Int) (x26 Int) (x27 Int)))))
+(declare-sort x30 0)
+(declare-sort x31 0)
+(declare-fun x32 () x31)
+(declare-datatypes () ((x36 (x35 (x33 Int) (x34 Int)))))
+(declare-fun x37 () x36)
+(declare-datatypes () ((x45 (x44 (x38 x5) (x39 x6) (x40 x6) (x41 x6) (x42 x36) (x43 x31)))))
+(declare-fun x47 (x12) x31)
+(declare-fun x46 (x31) x12)
+(declare-datatypes () ((x54 (x49 (x48 x22)) (x51 (x50 x29)) (d53 (s52 x12)))))
+(declare-fun x57 (x22) x29)
+(declare-fun x56 (x12) x22)
+(declare-fun x55 (x29) x22)
+(declare-fun x61 () (Array x6 x5))
+(declare-fun x66 () (Array x6 x17))
+(declare-fun x64 () (Array x6 x54))
+(declare-fun x67 () (Array x6 x54))
+(declare-fun x65 () (Array x6 x54))
+(declare-fun x62 () (Array x30 x45))
+(declare-fun x70 () (Array x30 x45))
+(declare-fun x68 () (Array x30 x45))
+(declare-fun x63 () x30)
+(declare-fun x59 (x22) x12)
+(declare-fun x60 (x29) x12)
+(declare-fun x58 (x12) x29)
+(declare-fun x71 () x6)
+(declare-fun x69 () x6)
+(assert
+(not
+ (=> (and
+ (forall ((x73 x30)) (=> (= x3 (x38 (select x62 x73))) (and (= (select x66 (x40 (select x62 x73))) x15) (= x3 (x7 (x40 (select x62 x73)))) (= (select x61 (x40 (select x62 x73))) x3) (= (x23 (ite (is-x49 (select x67 (x40 (select x62 x73)))) (let ((x74 (x48 (select x67 (x40 (select x62 x73)))))) (x57 x74)) (ite (is-x51 (select x67 (x40 (select x62 x73)))) (let ((x75 (x50 (select x67 (x40 (select x62 x73)))))) x75) (let ((x76 (s52 (select x67 (x40 (select x62 x73)))))) (x58 x76))))) x3))))
+ (forall ((x72 x6)) (=> (and (= x16 (select x66 x72)) (= (x7 x72) x3) (= (select x61 x72) x3)) (= (ite (is-d53 (select x67 x72)) x3 x4) x3))))
+
+ (= (ite (= (x38 (select x62 x63)) x3) (ite (and (=> (= (x40 (select x62 x63)) x69) (=> (= (x41 (select x62 x63)) x71) (=> (= x65 (store x67 x71 (d53 (x46 (x43 (select x62 x63)))))) (=> (= x70 (store x62 x63 (let ((x77 (select x62 x63))) (x44 (x38 x77) (x39 x77) (x40 x77) (x41 x77) (x42 x77) x32)))) (=> (= x68 (store x70 x63 (let ((x78 (select x70 x63))) (x44 x4 (x39 x78) (x40 x78) (x41 x78) (x42 x78) (x43 x78)))))
+ (=> (= (store x65 x69 (x51 (let ((x82 (ite (is-x49 (select x65 x69)) (let ((x79 (x48 (select x65 x69)))) (x57 x79)) (ite (is-x51 (select x65 x69)) (let ((x80 (x50 (select x65 x69)))) x80) (let ((x81 (s52 (select x65 x69)))) (x58 x81)))))) (x28 x4 x3 (x25 x82) (x26 x82) (+ (x27 (ite (is-x49 (select x65 x69)) (let ((x83 (x48 (select x65 x69)))) (x57 x83)) (ite (is-x51 (select x65 x69)) (let ((x84 (x50 (select x65 x69)))) x84) (let ((x85 (s52 (select x65 x69)))) (x58 x85))))) 1))))) x64) (forall ((x86 x6)) (=> (and (= x3 (x7 x86)) (= x3 (select x61 x86)) (= (select x66 x86) x16)) (= (ite (is-d53 (select x64 x86)) x3 x4) x3))))))))) (= x3 (x38 (select x62 x63)))) x3 x4) (ite (forall ((x87 x6)) (=> (and (= x3 (select x61 x87)) (= x3 (x7 x87)) (= x16 (select x66 x87))) (= x3 (ite (is-d53 (select x67 x87)) x3 x4)))) x3 x4)) x3))))
+(check-sat) \ No newline at end of file
diff --git a/test/regress/regress0/fmf/german169.smt2 b/test/regress/regress0/fmf/german169.smt2
new file mode 100644
index 000000000..f0906d6b5
--- /dev/null
+++ b/test/regress/regress0/fmf/german169.smt2
@@ -0,0 +1,104 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: sat
+; EXIT: 10
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(declare-datatypes () ((UNIT (Unit))))
+(declare-datatypes () ((BOOL (Truth) (Falsity))))
+
+; Decls --------------
+(declare-sort node$type 0)
+(declare-sort data$type 0)
+(declare-datatypes () ((cache_state$type (invalid) (shared) (exclusive))))
+(declare-datatypes () ((cache$type (c_cache$type (c_state cache_state$type) (c_data data$type)))))
+(declare-datatypes () ((msg_cmd$type (empty) (reqs) (reqe) (inv) (invack) (gnts) (gnte))))
+(declare-datatypes () ((msg$type (c_msg$type (m_cmd msg_cmd$type) (m_data data$type)))))
+(declare-fun dummy () data$type)
+
+; Var Decls --------------
+(declare-fun memdata$1 () data$type)
+(declare-fun shrset$1 () (Array node$type BOOL))
+(declare-fun recv_invack$i () node$type)
+(declare-fun exgntd () BOOL)
+(declare-fun chan3$1 () (Array node$type msg$type))
+(declare-fun shrset () (Array node$type BOOL))
+(declare-fun exgntd$1 () BOOL)
+(declare-fun chan2 () (Array node$type msg$type))
+(declare-fun chan3 () (Array node$type msg$type))
+(declare-fun auxnode () node$type)
+(declare-fun curcmd () msg_cmd$type)
+
+; Asserts --------------
+(assert (not (=> (and (and (forall ((n node$type))
+ (=> (= (m_cmd (select
+ chan2
+ n))
+ gnte) (= exgntd
+ Truth)))
+ (forall ((n node$type))
+ (=> (= exgntd Truth)
+ (= (select shrset n)
+ (ite (= n auxnode) Truth
+ Falsity))))) (forall
+ ((n node$type))
+ (=> (=
+ (m_cmd
+ (select
+ chan3
+ n))
+ invack)
+ (= (m_cmd
+ (select
+ chan2
+ n))
+ empty))))
+ (=> (= (m_cmd (select chan3 recv_invack$i))
+ invack) (=> (not (= curcmd empty))
+ (=> (= chan3$1 (store
+ chan3
+ recv_invack$i
+ (let (
+ (vup_228
+ (select
+ chan3
+ recv_invack$i)))
+ (c_msg$type
+ empty
+ (m_data
+ vup_228)))))
+ (=> (= shrset$1 (store
+ shrset
+ recv_invack$i
+ Falsity))
+ (= (ite (= exgntd Truth)
+ (ite (=> (= exgntd$1
+ Falsity)
+ (=> (= memdata$1
+ (m_data
+ (select
+ chan3$1
+ recv_invack$i)))
+ (forall (
+ (n node$type))
+ (=> (= (m_cmd
+ (select
+ chan2
+ n))
+ gnte)
+ (= exgntd$1
+ Truth)))))
+ Truth Falsity)
+ (ite (forall (
+ (n node$type))
+ (=> (= (m_cmd
+ (select
+ chan2
+ n))
+ gnte)
+ (= exgntd
+ Truth)))
+ Truth Falsity))
+ Truth))))))))
+
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/fmf/german73.smt2 b/test/regress/regress0/fmf/german73.smt2
new file mode 100644
index 000000000..388a53624
--- /dev/null
+++ b/test/regress/regress0/fmf/german73.smt2
@@ -0,0 +1,106 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: unsat
+; EXIT: 20
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+(declare-datatypes () ((UNIT (Unit))))
+(declare-datatypes () ((BOOL (Truth) (Falsity))))
+
+; Decls --------------
+(declare-sort node$type 0)
+(declare-sort data$type 0)
+(declare-datatypes () ((cache_state$type (invalid) (shared) (exclusive))))
+(declare-datatypes () ((cache$type (c_cache$type (c_state cache_state$type) (c_data data$type)))))
+(declare-datatypes () ((msg_cmd$type (empty) (reqs) (reqe) (inv) (invack) (gnts) (gnte))))
+(declare-datatypes () ((msg$type (c_msg$type (m_cmd msg_cmd$type) (m_data data$type)))))
+(declare-fun dummy () data$type)
+
+; Var Decls --------------
+(declare-fun memdata$1 () data$type)
+(declare-fun shrset$1 () (Array node$type BOOL))
+(declare-fun recv_invack$i () node$type)
+(declare-fun exgntd () BOOL)
+(declare-fun invset () (Array node$type BOOL))
+(declare-fun chan3$1 () (Array node$type msg$type))
+(declare-fun shrset () (Array node$type BOOL))
+(declare-fun exgntd$1 () BOOL)
+(declare-fun chan2 () (Array node$type msg$type))
+(declare-fun chan3 () (Array node$type msg$type))
+(declare-fun curcmd () msg_cmd$type)
+
+; Asserts --------------
+(assert (not (=> (and (forall ((n node$type))
+ (=> (= (select invset n)
+ Truth) (= (select
+ shrset
+ n) Truth)))
+ (forall ((n node$type)) (=>
+ (or
+ (=
+ (m_cmd
+ (select
+ chan2
+ n))
+ inv)
+ (=
+ (m_cmd
+ (select
+ chan3
+ n))
+ invack))
+ (not
+ (=
+ (select
+ invset
+ n)
+ Truth)))))
+ (=> (= (m_cmd (select chan3 recv_invack$i))
+ invack) (=> (not (= curcmd empty))
+ (=> (= chan3$1 (store
+ chan3
+ recv_invack$i
+ (let (
+ (vup_101
+ (select
+ chan3
+ recv_invack$i)))
+ (c_msg$type
+ empty
+ (m_data
+ vup_101)))))
+ (=> (= shrset$1 (store
+ shrset
+ recv_invack$i
+ Falsity))
+ (= (ite (= exgntd Truth)
+ (ite (=> (= exgntd$1
+ Falsity)
+ (=> (= memdata$1
+ (m_data
+ (select
+ chan3$1
+ recv_invack$i)))
+ (forall (
+ (n node$type))
+ (=> (= (select
+ invset
+ n)
+ Truth)
+ (= (select
+ shrset$1
+ n) Truth)))))
+ Truth Falsity)
+ (ite (forall (
+ (n node$type))
+ (=> (= (select
+ invset
+ n)
+ Truth)
+ (= (select
+ shrset$1
+ n) Truth)))
+ Truth Falsity))
+ Truth))))))))
+
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/fmf/refcount24.cvc.smt2 b/test/regress/regress0/fmf/refcount24.cvc.smt2
new file mode 100644
index 000000000..bf042c9b2
--- /dev/null
+++ b/test/regress/regress0/fmf/refcount24.cvc.smt2
@@ -0,0 +1,38 @@
+; COMMAND-LINE: --finite-model-find
+; EXPECT: sat
+; EXIT: 10
+(set-logic ALL_SUPPORTED)
+(set-info :smt-lib-version 2.0)
+(set-info :category "unknown")
+(set-info :status sat)
+(declare-datatypes ()
+((UNIT (Unit))
+))
+(declare-datatypes ()
+((BOOL (Truth) (Falsity))
+))
+(declare-sort resource$type 0)
+(declare-sort process$type 0)
+(declare-fun null () resource$type)
+(declare-sort S$t$type 0)
+(declare-fun S$empty () S$t$type)
+(declare-fun S$mem (process$type S$t$type) BOOL)
+(declare-fun S$add (process$type S$t$type) S$t$type)
+(declare-fun S$remove (process$type S$t$type) S$t$type)
+(declare-fun S$cardinality (S$t$type) Int)
+(assert (forall ((e process$type)) (not (= (S$mem e S$empty) Truth))))
+(assert (forall ((x process$type) (y process$type) (s S$t$type)) (= (S$mem x (S$add y s)) (ite (or (= x y) (= (S$mem x s) Truth)) Truth Falsity))))
+(assert (forall ((x process$type) (y process$type) (s S$t$type)) (= (S$mem x (S$remove y s)) (ite (and (not (= x y)) (= (S$mem x s) Truth)) Truth Falsity))))
+(assert (= (S$cardinality S$empty) 0))
+(assert (forall ((s S$t$type)) (=> (= (S$cardinality s) 0) (= s S$empty))))
+(assert (forall ((s S$t$type)) (>= (S$cardinality s) 0)))
+(assert (forall ((x process$type) (s S$t$type)) (let ((?v_0 (S$cardinality s))) (= (S$cardinality (S$add x s)) (ite (= (S$mem x s) Truth) ?v_0 (+ ?v_0 1))))))
+(assert (forall ((x process$type) (s S$t$type)) (let ((?v_0 (S$cardinality s))) (= (S$cardinality (S$remove x s)) (ite (= (S$mem x s) Truth) (- ?v_0 1) ?v_0)))))
+(declare-fun count () (Array resource$type Int))
+(declare-fun ref () (Array process$type resource$type))
+(declare-fun valid () (Array resource$type BOOL))
+(declare-fun destroy$r () resource$type)
+(declare-fun valid$1 () (Array resource$type BOOL))
+(assert (not (=> (forall ((p process$type)) (let ((?v_0 (select ref p))) (=> (not (= ?v_0 null)) (= (select valid ?v_0) Truth)))) (=> (not (= destroy$r null)) (=> (= (select valid destroy$r) Truth) (=> (= (select count destroy$r) 0) (=> (= valid$1 (store valid destroy$r Falsity)) (forall ((p process$type)) (let ((?v_1 (select ref p))) (=> (not (= ?v_1 null)) (= (select valid$1 ?v_1) Truth)))))))))))
+(check-sat)
+(exit)
diff --git a/test/regress/regress0/lemmas/Makefile.am b/test/regress/regress0/lemmas/Makefile.am
index 126b206ab..260b3600d 100644
--- a/test/regress/regress0/lemmas/Makefile.am
+++ b/test/regress/regress0/lemmas/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/precedence/Makefile.am b/test/regress/regress0/precedence/Makefile.am
index 4b8b4a05d..141510ea2 100644
--- a/test/regress/regress0/precedence/Makefile.am
+++ b/test/regress/regress0/precedence/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/preprocess/Makefile.am b/test/regress/regress0/preprocess/Makefile.am
index fe02b230e..73d13e78d 100644
--- a/test/regress/regress0/preprocess/Makefile.am
+++ b/test/regress/regress0/preprocess/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/push-pop/Makefile.am b/test/regress/regress0/push-pop/Makefile.am
index 0032c5645..0a1094238 100644
--- a/test/regress/regress0/push-pop/Makefile.am
+++ b/test/regress/regress0/push-pop/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = boolean arith .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -38,8 +42,7 @@ TESTS = $(SMT_TESTS) $(SMT2_TESTS) $(CVC_TESTS) $(BUG_TESTS)
EXTRA_DIST = $(TESTS) \
bug216.smt2.expect \
- bug396.smt2 \
- bug394.smt2
+ bug396.smt2
# synonyms for "check" in this directory
.PHONY: regress regress0 test
diff --git a/test/regress/regress0/push-pop/arith/Makefile.am b/test/regress/regress0/push-pop/arith/Makefile.am
index 7171e6e21..6fd183ec3 100644
--- a/test/regress/regress0/push-pop/arith/Makefile.am
+++ b/test/regress/regress0/push-pop/arith/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/push-pop/boolean/Makefile.am b/test/regress/regress0/push-pop/boolean/Makefile.am
index 5b12f59fa..0757ebfc2 100644
--- a/test/regress/regress0/push-pop/boolean/Makefile.am
+++ b/test/regress/regress0/push-pop/boolean/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/quantifiers/Makefile.am b/test/regress/regress0/quantifiers/Makefile.am
index 3e04c8437..0b74d83b7 100644
--- a/test/regress/regress0/quantifiers/Makefile.am
+++ b/test/regress/regress0/quantifiers/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -35,9 +39,8 @@ TESTS = \
smtlib384a03.smt2 \
smtlib46f14a.smt2 \
smtlibf957ea.smt2 \
- gauss_init_0030.fof.smt2 \
- piVC_5581bd.smt2
-
+ gauss_init_0030.fof.smt2
+
# regression can be solved with --finite-model-find --fmf-inst-engine
# set3.smt2
diff --git a/test/regress/regress0/rewriterules/Makefile.am b/test/regress/regress0/rewriterules/Makefile.am
index 175088733..d2e748fbf 100644
--- a/test/regress/regress0/rewriterules/Makefile.am
+++ b/test/regress/regress0/rewriterules/Makefile.am
@@ -1,7 +1,11 @@
CVC4_REGRESSION_ARGS ?= --efficient-e-matching
export CVC4_REGRESSION_ARGS
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/strings/Makefile b/test/regress/regress0/strings/Makefile
new file mode 100644
index 000000000..1c399b3e4
--- /dev/null
+++ b/test/regress/regress0/strings/Makefile
@@ -0,0 +1,8 @@
+topdir = ../../../..
+srcdir = test/regress/regress0/strings
+
+include $(topdir)/Makefile.subdir
+
+# synonyms for "check"
+.PHONY: test
+test: check
diff --git a/test/regress/regress0/strings/Makefile.am b/test/regress/regress0/strings/Makefile.am
new file mode 100644
index 000000000..a1ae66a5f
--- /dev/null
+++ b/test/regress/regress0/strings/Makefile.am
@@ -0,0 +1,52 @@
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
+LOG_COMPILER = @srcdir@/../../run_regression
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+
+if AUTOMAKE_1_11
+# old-style (pre-automake 1.12) test harness
+TESTS_ENVIRONMENT = \
+ $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(AM_LOG_FLAGS) $(LOG_FLAGS)
+endif
+
+MAKEFLAGS = -k
+
+# These are run for all build profiles.
+# If a test shouldn't be run in e.g. competition mode,
+# put it below in "TESTS +="
+TESTS = \
+ cardinality.smt2 \
+ str001.smt2 \
+ str002.smt2 \
+ str003.smt2 \
+ str004.smt2 \
+ str005.smt2 \
+ model001.smt2 \
+ loop001.smt2 \
+ loop003.smt2 \
+ loop007.smt2
+
+# loop002.smt2
+# loop004.smt2
+# loop005.smt2
+# loop006.smt2
+
+FAILING_TESTS =
+
+EXTRA_DIST = $(TESTS)
+
+
+# and make sure to distribute it
+EXTRA_DIST +=
+
+# synonyms for "check"
+.PHONY: regress regress0 test
+regress regress0 test: check
+
+# do nothing in this subdir
+.PHONY: regress1 regress2 regress3
+regress1 regress2 regress3:
diff --git a/test/regress/regress0/strings/cardinality.smt2 b/test/regress/regress0/strings/cardinality.smt2
new file mode 100644
index 000000000..465ea0b5e
--- /dev/null
+++ b/test/regress/regress0/strings/cardinality.smt2
@@ -0,0 +1,23 @@
+(set-logic QF_S)
+(set-info :status unsat)
+
+(set-option :str-alphabet-card 2)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+(declare-fun w () String)
+(declare-fun i () Int)
+
+(assert (= i 1))
+(assert (= (str.len x) i))
+(assert (= (str.len y) i))
+(assert (= (str.len z) i))
+(assert (= (str.len w) 2))
+
+(assert (not (= x y)))
+(assert (not (= x z)))
+(assert (not (= z y)))
+
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop001.smt2 b/test/regress/regress0/strings/loop001.smt2
new file mode 100644
index 000000000..11460b335
--- /dev/null
+++ b/test/regress/regress0/strings/loop001.smt2
@@ -0,0 +1,13 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status unsat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+(declare-fun w () String)
+(declare-fun w1 () String)
+(declare-fun w2 () String)
+
+(assert (= (str.++ x "a") (str.++ "b" x)))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop002.smt2 b/test/regress/regress0/strings/loop002.smt2
new file mode 100644
index 000000000..2f96241dc
--- /dev/null
+++ b/test/regress/regress0/strings/loop002.smt2
@@ -0,0 +1,10 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+
+(assert (= (str.++ x "ba") (str.++ "ab" x)))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop003.smt2 b/test/regress/regress0/strings/loop003.smt2
new file mode 100644
index 000000000..b4fbcf7d5
--- /dev/null
+++ b/test/regress/regress0/strings/loop003.smt2
@@ -0,0 +1,13 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+(declare-fun w () String)
+(declare-fun w1 () String)
+(declare-fun w2 () String)
+
+(assert (= (str.++ x "aaaae") (str.++ "eaaaa" x)))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop004.smt2 b/test/regress/regress0/strings/loop004.smt2
new file mode 100644
index 000000000..8d2ff8096
--- /dev/null
+++ b/test/regress/regress0/strings/loop004.smt2
@@ -0,0 +1,13 @@
+(set-logic QF_S)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+(declare-fun w () String)
+(declare-fun w1 () String)
+(declare-fun w2 () String)
+
+(assert (= (str.++ x y z) (str.++ y z x)))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop005.smt2 b/test/regress/regress0/strings/loop005.smt2
new file mode 100644
index 000000000..6e5fc96d4
--- /dev/null
+++ b/test/regress/regress0/strings/loop005.smt2
@@ -0,0 +1,20 @@
+; COMMAND-LINE: --no-check-models
+; EXPECT: sat
+; EXIT: 10
+;
+(set-logic QF_S)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+(declare-fun w () String)
+(declare-fun w1 () String)
+(declare-fun w2 () String)
+
+(assert (= (str.++ x y z) (str.++ x z y)))
+(assert (= (str.++ x w z) (str.++ x z w)))
+(assert (not (= y w)))
+(assert (> (str.len z) 0))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop006.smt2 b/test/regress/regress0/strings/loop006.smt2
new file mode 100644
index 000000000..288a5f60c
--- /dev/null
+++ b/test/regress/regress0/strings/loop006.smt2
@@ -0,0 +1,15 @@
+(set-logic QF_S)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+(declare-fun w () String)
+(declare-fun w1 () String)
+(declare-fun w2 () String)
+
+;(assert (= (str.++ x y) (str.++ y x)))
+
+(assert (not (= (str.++ x y) (str.++ y x))))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/loop007.smt2 b/test/regress/regress0/strings/loop007.smt2
new file mode 100644
index 000000000..0534d8b53
--- /dev/null
+++ b/test/regress/regress0/strings/loop007.smt2
@@ -0,0 +1,10 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+
+(assert (= (str.++ x y "aa") (str.++ "aa" y x)))
+(assert (= (str.len x) 1))
+
+(check-sat) \ No newline at end of file
diff --git a/test/regress/regress0/strings/model001.smt2 b/test/regress/regress0/strings/model001.smt2
new file mode 100644
index 000000000..2832b5c96
--- /dev/null
+++ b/test/regress/regress0/strings/model001.smt2
@@ -0,0 +1,12 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :produce-models true)
+
+(declare-fun x () String)
+(declare-fun y () String)
+
+(assert (not (= x y)))
+(assert (= (str.len x) (str.len y)))
+
+(check-sat)
+;(get-model)
diff --git a/test/regress/regress0/strings/str001.smt2 b/test/regress/regress0/strings/str001.smt2
new file mode 100644
index 000000000..bb2b701d8
--- /dev/null
+++ b/test/regress/regress0/strings/str001.smt2
@@ -0,0 +1,16 @@
+(set-logic QF_S)
+(set-info :status unsat)
+
+(declare-fun xx () String)
+(declare-fun yy () String)
+(declare-fun zz () String)
+(declare-fun ww () String)
+(declare-fun pp () String)
+(declare-fun qq () String)
+
+(assert (= (str.++ xx yy zz) (str.++ ww qq)))
+(assert (= ww (str.++ xx pp)))
+(assert (= yy pp))
+(assert (not (= zz qq)))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/str002.smt2 b/test/regress/regress0/strings/str002.smt2
new file mode 100644
index 000000000..62512ef79
--- /dev/null
+++ b/test/regress/regress0/strings/str002.smt2
@@ -0,0 +1,18 @@
+(set-logic QF_S)
+(set-info :status unsat)
+
+(declare-fun xx () String)
+(declare-fun yy () String)
+(declare-fun zz () String)
+(declare-fun ww () String)
+(declare-fun pp () String)
+(declare-fun qq () String)
+
+; assoc
+(assert (or (= xx (str.++ yy "aa")) (= zz (str.++ yy "aa"))
+))
+(assert (and (not (= (str.++ xx "bb") (str.++ yy "aa" "bb")))
+ (not (= (str.++ zz "bb") (str.++ yy "aa" "bb")))
+))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/str003.smt2 b/test/regress/regress0/strings/str003.smt2
new file mode 100644
index 000000000..0ced7f447
--- /dev/null
+++ b/test/regress/regress0/strings/str003.smt2
@@ -0,0 +1,15 @@
+(set-logic QF_S)
+(set-info :status unsat)
+
+(declare-fun xx () String)
+(declare-fun yy () String)
+(declare-fun zz () String)
+(declare-fun ww () String)
+(declare-fun pp () String)
+(declare-fun qq () String)
+
+(assert (= "ab" (str.++ "a" xx)))
+(assert (not (= xx yy)))
+(assert (= "b" yy))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/str004.smt2 b/test/regress/regress0/strings/str004.smt2
new file mode 100644
index 000000000..8a03f4481
--- /dev/null
+++ b/test/regress/regress0/strings/str004.smt2
@@ -0,0 +1,15 @@
+(set-logic QF_S)
+(set-info :status unsat)
+
+(declare-fun xx () String)
+(declare-fun yy () String)
+(declare-fun zz () String)
+(declare-fun ww () String)
+(declare-fun pp () String)
+(declare-fun qq () String)
+
+; Morgan says it needs length bound
+(assert (> (str.len yy) (str.len xx)))
+(assert (= xx (str.++ xx yy)))
+
+(check-sat)
diff --git a/test/regress/regress0/strings/str005.smt2 b/test/regress/regress0/strings/str005.smt2
new file mode 100644
index 000000000..84cb5af01
--- /dev/null
+++ b/test/regress/regress0/strings/str005.smt2
@@ -0,0 +1,18 @@
+(set-logic QF_S)
+(set-info :status unsat)
+
+(declare-fun xx () String)
+(declare-fun yy () String)
+(declare-fun zz () String)
+(declare-fun ww () String)
+(declare-fun pp () String)
+(declare-fun qq () String)
+
+; common postfix
+;(assert (= (str.++ xx "aa") (str.++ xx "bb")))
+
+(assert (= (str.len yy) 0))
+(assert (not (= yy "")))
+
+(check-sat)
+
diff --git a/test/regress/regress0/tptp/ARI086=1.p b/test/regress/regress0/tptp/ARI086=1.p
new file mode 100644
index 000000000..f6d2fcb28
--- /dev/null
+++ b/test/regress/regress0/tptp/ARI086=1.p
@@ -0,0 +1,32 @@
+%------------------------------------------------------------------------------
+% File : ARI086=1 : TPTP v5.5.0. Released v5.0.0.
+% Domain : Arithmetic
+% Problem : Integer: Sum 2 and 2 is 5
+% Version : Especial.
+% English :
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : CounterSatisfiable
+% Rating : 0.00 v5.2.0, 1.00 v5.0.0
+% Syntax : Number of formulae : 1 ( 1 unit; 0 type)
+% Number of atoms : 1 ( 1 equality)
+% Maximal formula depth : 1 ( 1 average)
+% Number of connectives : 0 ( 0 ~; 0 |; 0 &)
+% ( 0 <=>; 0 =>; 0 <=; 0 <~>)
+% ( 0 ~|; 0 ~&)
+% Number of type conns : 0 ( 0 >; 0 *; 0 +; 0 <<)
+% Number of predicates : 1 ( 0 propositional; 2-2 arity)
+% Number of functors : 3 ( 2 constant; 0-2 arity)
+% Number of variables : 0 ( 0 sgn; 0 !; 0 ?)
+% Maximal term depth : 2 ( 2 average)
+% Arithmetic symbols : 3 ( 0 pred; 1 func; 2 numbers)
+% SPC : TFF_CSA_EQU_ARI
+
+% Comments :
+%------------------------------------------------------------------------------
+tff(anti_sum_2_2_5,conjecture,
+ ( $sum(2,2) = 5 )).
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/Axioms/BOO004-0.ax b/test/regress/regress0/tptp/Axioms/BOO004-0.ax
new file mode 100644
index 000000000..e02b4c2f8
--- /dev/null
+++ b/test/regress/regress0/tptp/Axioms/BOO004-0.ax
@@ -0,0 +1,48 @@
+%--------------------------------------------------------------------------
+% File : BOO004-0 : TPTP v5.5.0. Released v1.0.0.
+% Domain : Boolean Algebra
+% Axioms : Boolean algebra (equality) axioms
+% Version : [Ver94] (equality) axioms.
+% English :
+
+% Refs : [Ver94] Veroff (1994), Problem Set
+% Source : [Ver94]
+% Names :
+
+% Status : Satisfiable
+% Syntax : Number of clauses : 8 ( 0 non-Horn; 8 unit; 0 RR)
+% Number of atoms : 8 ( 8 equality)
+% Maximal clause size : 1 ( 1 average)
+% Number of predicates : 1 ( 0 propositional; 2-2 arity)
+% Number of functors : 5 ( 2 constant; 0-2 arity)
+% Number of variables : 14 ( 0 singleton)
+% Maximal term depth : 3 ( 2 average)
+% SPC :
+
+% Comments :
+%--------------------------------------------------------------------------
+cnf(commutativity_of_add,axiom,
+ ( add(X,Y) = add(Y,X) )).
+
+cnf(commutativity_of_multiply,axiom,
+ ( multiply(X,Y) = multiply(Y,X) )).
+
+cnf(distributivity1,axiom,
+ ( add(X,multiply(Y,Z)) = multiply(add(X,Y),add(X,Z)) )).
+
+cnf(distributivity2,axiom,
+ ( multiply(X,add(Y,Z)) = add(multiply(X,Y),multiply(X,Z)) )).
+
+cnf(additive_id1,axiom,
+ ( add(X,additive_identity) = X )).
+
+cnf(multiplicative_id1,axiom,
+ ( multiply(X,multiplicative_identity) = X )).
+
+cnf(additive_inverse1,axiom,
+ ( add(X,inverse(X)) = multiplicative_identity )).
+
+cnf(multiplicative_inverse1,axiom,
+ ( multiply(X,inverse(X)) = additive_identity )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/Axioms/SYN000+0.ax b/test/regress/regress0/tptp/Axioms/SYN000+0.ax
new file mode 100644
index 000000000..24ef682b7
--- /dev/null
+++ b/test/regress/regress0/tptp/Axioms/SYN000+0.ax
@@ -0,0 +1,37 @@
+%------------------------------------------------------------------------------
+% File : SYN000+0 : TPTP v5.5.0. Released v3.6.0.
+% Domain : Syntactic
+% Axioms : A simple include file for FOF
+% Version : Biased.
+% English :
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Syntax : Number of formulae : 3 ( 3 unit)
+% Number of atoms : 3 ( 0 equality)
+% Maximal formula depth : 1 ( 1 average)
+% Number of connectives : 0 ( 0 ~ ; 0 |; 0 &)
+% ( 0 <=>; 0 =>; 0 <=)
+% ( 0 <~>; 0 ~|; 0 ~&)
+% Number of predicates : 3 ( 3 propositional; 0-0 arity)
+% Number of functors : 0 ( 0 constant; --- arity)
+% Number of variables : 0 ( 0 singleton; 0 !; 0 ?)
+% Maximal term depth : 0 ( 0 average)
+% SPC :
+
+% Comments :
+%------------------------------------------------------------------------------
+%----Some axioms to include
+fof(ia1,axiom,
+ ia1).
+
+fof(ia2,axiom,
+ ia2).
+
+fof(ia3,axiom,
+ ia3).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/Axioms/SYN000-0.ax b/test/regress/regress0/tptp/Axioms/SYN000-0.ax
new file mode 100644
index 000000000..d67e61aee
--- /dev/null
+++ b/test/regress/regress0/tptp/Axioms/SYN000-0.ax
@@ -0,0 +1,34 @@
+%------------------------------------------------------------------------------
+% File : SYN000-0 : TPTP v5.5.0. Released v3.6.0.
+% Domain : Syntactic
+% Axioms : A simple include file for CNF
+% Version : Biased.
+% English :
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Syntax : Number of clauses : 3 ( 0 non-Horn; 3 unit; 3 RR)
+% Number of atoms : 3 ( 0 equality)
+% Maximal clause size : 1 ( 1 average)
+% Number of predicates : 3 ( 3 propositional; 0-0 arity)
+% Number of functors : 0 ( 0 constant; --- arity)
+% Number of variables : 0 ( 0 singleton)
+% Maximal term depth : 0 ( 0 average)
+% SPC :
+
+% Comments :
+%------------------------------------------------------------------------------
+%----Some axioms to include
+cnf(ia1,axiom,
+ ia1).
+
+cnf(ia2,axiom,
+ ia2).
+
+cnf(ia3,axiom,
+ ia3).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/Axioms/SYN000_0.ax b/test/regress/regress0/tptp/Axioms/SYN000_0.ax
new file mode 100644
index 000000000..acb557ef4
--- /dev/null
+++ b/test/regress/regress0/tptp/Axioms/SYN000_0.ax
@@ -0,0 +1,47 @@
+%------------------------------------------------------------------------------
+% File : SYN000_0 : TPTP v5.5.0. Released v5.0.0.
+% Domain : Syntactic
+% Axioms : A simple include file for TFF
+% Version : Biased.
+% English :
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Syntax : Number of formulae : 6 ( 6 unit; 3 type)
+% Number of atoms : 6 ( 0 equality)
+% Maximal formula depth : 2 ( 2 average)
+% Number of connectives : 0 ( 0 ~; 0 |; 0 &)
+% ( 0 <=>; 0 =>; 0 <=; 0 <~>)
+% ( 0 ~|; 0 ~&)
+% Number of type conns : 0 ( 0 >; 0 *; 0 +; 0 <<)
+% Number of predicates : 4 ( 4 propositional; 0-0 arity)
+% Number of functors : 0 ( 0 constant; --- arity)
+% Number of variables : 0 ( 0 sgn; 0 !; 0 ?)
+% Maximal term depth : 0 ( 0 average)
+% SPC :
+
+% Comments :
+%------------------------------------------------------------------------------
+%----Some axioms to include
+tff(ia1_type,type,(
+ ia1: $o )).
+
+tff(ia2_type,type,(
+ ia2: $o )).
+
+tff(ia3_type,type,(
+ ia3: $o )).
+
+tff(ia1,axiom,(
+ ia1 )).
+
+tff(ia2,axiom,(
+ ia2 )).
+
+tff(ia3,axiom,(
+ ia3 )).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/BOO003-4.p b/test/regress/regress0/tptp/BOO003-4.p
new file mode 100644
index 000000000..0ea15fefc
--- /dev/null
+++ b/test/regress/regress0/tptp/BOO003-4.p
@@ -0,0 +1,31 @@
+%--------------------------------------------------------------------------
+% File : BOO003-4 : TPTP v5.5.0. Released v1.1.0.
+% Domain : Boolean Algebra
+% Problem : Multiplication is idempotent (X * X = X)
+% Version : [Ver94] (equality) axioms.
+% English :
+
+% Refs : [Ver94] Veroff (1994), Problem Set
+% Source : [Ver94]
+% Names : TA [Ver94]
+
+% Status : Unsatisfiable
+% Rating : 0.10 v5.5.0, 0.05 v5.4.0, 0.00 v2.1.0, 0.13 v2.0.0
+% Syntax : Number of clauses : 9 ( 0 non-Horn; 9 unit; 1 RR)
+% Number of atoms : 9 ( 9 equality)
+% Maximal clause size : 1 ( 1 average)
+% Number of predicates : 1 ( 0 propositional; 2-2 arity)
+% Number of functors : 6 ( 3 constant; 0-2 arity)
+% Number of variables : 14 ( 0 singleton)
+% Maximal term depth : 3 ( 2 average)
+% SPC : CNF_UNS_RFO_PEQ_UEQ
+
+% Comments :
+%--------------------------------------------------------------------------
+%----Include boolean algebra axioms for equality formulation
+include('Axioms/BOO004-0.ax').
+%--------------------------------------------------------------------------
+cnf(prove_a_times_a_is_a,negated_conjecture,
+ ( multiply(a,a) != a )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/BOO027-1.p b/test/regress/regress0/tptp/BOO027-1.p
new file mode 100644
index 000000000..a3cd4224c
--- /dev/null
+++ b/test/regress/regress0/tptp/BOO027-1.p
@@ -0,0 +1,48 @@
+%--------------------------------------------------------------------------
+% File : BOO027-1 : TPTP v5.5.0. Released v2.2.0.
+% Domain : Boolean Algebra
+% Problem : Independence of self-dual 2-basis.
+% Version : [MP96] (eqiality) axioms : Especial.
+% English : Show that half of the self-dual 2-basis in DUAL-BA-3 is not
+% a basis for Boolean Algebra.
+
+% Refs : [McC98] McCune (1998), Email to G. Sutcliffe
+% : [MP96] McCune & Padmanabhan (1996), Automated Deduction in Eq
+% Source : [McC98]
+% Names : DUAL-BA-4 [MP96]
+
+% Status : Satisfiable
+% Rating : 0.00 v5.5.0, 0.20 v5.4.0, 0.25 v5.3.0, 0.33 v5.2.0, 0.00 v3.2.0, 0.33 v3.1.0, 0.00 v2.2.1
+% Syntax : Number of clauses : 6 ( 0 non-Horn; 6 unit; 1 RR)
+% Number of atoms : 6 ( 6 equality)
+% Maximal clause size : 1 ( 1 average)
+% Number of predicates : 1 ( 0 propositional; 2-2 arity)
+% Number of functors : 5 ( 2 constant; 0-2 arity)
+% Number of variables : 10 ( 0 singleton)
+% Maximal term depth : 5 ( 3 average)
+% SPC : CNF_SAT_RFO_PEQ_UEQ
+
+% Comments : There is a 2-element model.
+%--------------------------------------------------------------------------
+%----Two properties of Boolean algebra:
+cnf(multiply_add_property,axiom,
+ ( multiply(X,add(Y,Z)) = add(multiply(Y,X),multiply(Z,X)) )).
+
+cnf(additive_inverse,axiom,
+ ( add(X,inverse(X)) = one )).
+
+%----Pixley properties:
+cnf(pixley1,axiom,
+ ( add(multiply(X,inverse(X)),add(multiply(X,Y),multiply(inverse(X),Y))) = Y )).
+
+cnf(pixley2,axiom,
+ ( add(multiply(X,inverse(Y)),add(multiply(X,Y),multiply(inverse(Y),Y))) = X )).
+
+cnf(pixley3,axiom,
+ ( add(multiply(X,inverse(Y)),add(multiply(X,X),multiply(inverse(Y),X))) = X )).
+
+%----Denial of a property of Boolean Algebra:
+cnf(prove_idempotence,negated_conjecture,
+ ( add(a,a) != a )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/DAT001=1.p b/test/regress/regress0/tptp/DAT001=1.p
new file mode 100644
index 000000000..922a6cfc3
--- /dev/null
+++ b/test/regress/regress0/tptp/DAT001=1.p
@@ -0,0 +1,57 @@
+%------------------------------------------------------------------------------
+% File : DAT001=1 : TPTP v5.5.0. Released v5.0.0.
+% Domain : Data Structures
+% Problem : Recursive list sort
+% Version : Especial.
+% English :
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Theorem
+% Rating : 0.12 v5.5.0, 0.25 v5.4.0, 0.38 v5.3.0, 0.29 v5.2.0, 0.20 v5.1.0, 0.25 v5.0.0
+% Syntax : Number of formulae : 8 ( 5 unit; 4 type)
+% Number of atoms : 13 ( 0 equality)
+% Maximal formula depth : 6 ( 3 average)
+% Number of connectives : 2 ( 0 ~; 0 |; 1 &)
+% ( 0 <=>; 1 =>; 0 <=; 0 <~>)
+% ( 0 ~|; 0 ~&)
+% Number of type conns : 3 ( 2 >; 1 *; 0 +; 0 <<)
+% Number of predicates : 9 ( 7 propositional; 0-2 arity)
+% Number of functors : 7 ( 6 constant; 0-2 arity)
+% Number of variables : 4 ( 0 sgn; 4 !; 0 ?)
+% Maximal term depth : 6 ( 2 average)
+% Arithmetic symbols : 7 ( 2 pred; 0 func; 5 numbers)
+% SPC : TFF_THM_NEQ_ARI
+
+% Comments :
+%------------------------------------------------------------------------------
+tff(list_type,type,(
+ list: $tType )).
+
+tff(nil_type,type,(
+ nil: list )).
+
+tff(mycons_type,type,(
+ mycons: ( $int * list ) > list )).
+
+tff(sorted_type,type,(
+ sorted: list > $o )).
+
+tff(empty_is_sorted,axiom,(
+ sorted(nil) )).
+
+tff(single_is_sorted,axiom,(
+ ! [X: $int] : sorted(mycons(X,nil)) )).
+
+tff(recursive_sort,axiom,(
+ ! [X: $int,Y: $int,R: list] :
+ ( ( $less(X,Y)
+ & sorted(mycons(Y,R)) )
+ => sorted(mycons(X,mycons(Y,R))) ) )).
+
+tff(check_list,conjecture,(
+ sorted(mycons(1,mycons(2,mycons(4,mycons(7,mycons(100,nil)))))) )).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/KRS018+1.p b/test/regress/regress0/tptp/KRS018+1.p
new file mode 100644
index 000000000..91039877b
--- /dev/null
+++ b/test/regress/regress0/tptp/KRS018+1.p
@@ -0,0 +1,55 @@
+%------------------------------------------------------------------------------
+% File : KRS018+1 : TPTP v5.5.0. Released v3.1.0.
+% Domain : Knowledge Representation (Semantic Web)
+% Problem : Nothing can be defined using OWL Lite restrictions
+% Version : Especial.
+% English :
+
+% Refs : [Bec03] Bechhofer (2003), Email to G. Sutcliffe
+% : [TR+04] Tsarkov et al. (2004), Using Vampire to Reason with OW
+% Source : [Bec03]
+% Names : consistent_I5.2-Manifest001 [Bec03]
+
+% Status : Satisfiable
+% Rating : 0.00 v4.1.0, 0.25 v4.0.1, 0.00 v3.1.0
+% Syntax : Number of formulae : 4 ( 0 unit)
+% Number of atoms : 8 ( 0 equality)
+% Maximal formula depth : 5 ( 4 average)
+% Number of connectives : 7 ( 3 ~ ; 0 |; 1 &)
+% ( 1 <=>; 2 =>; 0 <=)
+% ( 0 <~>; 0 ~|; 0 ~&)
+% Number of predicates : 6 ( 0 propositional; 1-2 arity)
+% Number of functors : 0 ( 0 constant; --- arity)
+% Number of variables : 6 ( 0 singleton; 4 !; 2 ?)
+% Maximal term depth : 1 ( 1 average)
+% SPC : FOF_SAT_RFO_NEQ
+
+% Comments : Sean Bechhofer says there are some errors in the encoding of
+% datatypes, so this problem may not be perfect. At least it's
+% still representative of the type of reasoning required for OWL.
+%------------------------------------------------------------------------------
+%----Thing and Nothing
+fof(axiom_0,axiom,
+ ( ! [X] :
+ ( cowlThing(X)
+ & ~ cowlNothing(X) ) )).
+
+%----String and Integer disjoint
+fof(axiom_1,axiom,
+ ( ! [X] :
+ ( xsd_string(X)
+ <=> ~ xsd_integer(X) ) )).
+
+%----Super cNothing
+fof(axiom_2,axiom,
+ ( ! [X] :
+ ( cNothing(X)
+ => ~ ( ? [Y] : rp(X,Y) ) ) )).
+
+%----Super cNothing
+fof(axiom_3,axiom,
+ ( ! [X] :
+ ( cNothing(X)
+ => ? [Y0] : rp(X,Y0) ) )).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/KRS063+1.p b/test/regress/regress0/tptp/KRS063+1.p
new file mode 100644
index 000000000..737741dee
--- /dev/null
+++ b/test/regress/regress0/tptp/KRS063+1.p
@@ -0,0 +1,181 @@
+%------------------------------------------------------------------------------
+% File : KRS063+1 : TPTP v5.5.0. Released v3.1.0.
+% Domain : Knowledge Representation (Semantic Web)
+% Problem : An example combining owl:oneOf and owl:inverseOf
+% Version : Especial.
+% English :
+
+% Refs : [Bec03] Bechhofer (2003), Email to G. Sutcliffe
+% : [TR+04] Tsarkov et al. (2004), Using Vampire to Reason with OW
+% Source : [Bec03]
+% Names : inconsistent_I4.5-Manifest002 [Bec03]
+
+% Status : Unsatisfiable
+% Rating : 0.00 v3.1.0
+% Syntax : Number of formulae : 27 ( 9 unit)
+% Number of atoms : 63 ( 18 equality)
+% Maximal formula depth : 8 ( 4 average)
+% Number of connectives : 39 ( 3 ~ ; 5 |; 14 &)
+% ( 4 <=>; 13 =>; 0 <=)
+% ( 0 <~>; 0 ~|; 0 ~&)
+% Number of predicates : 11 ( 0 propositional; 1-2 arity)
+% Number of functors : 7 ( 7 constant; 0-0 arity)
+% Number of variables : 37 ( 0 singleton; 36 !; 1 ?)
+% Maximal term depth : 1 ( 1 average)
+% SPC : FOF_UNS_RFO_SEQ
+
+% Comments : Sean Bechhofer says there are some errors in the encoding of
+% datatypes, so this problem may not be perfect. At least it's
+% still representative of the type of reasoning required for OWL.
+%------------------------------------------------------------------------------
+fof(cEUCountry_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & cEUCountry(A) )
+ => cEUCountry(B) ) )).
+
+fof(cEuroMP_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & cEuroMP(A) )
+ => cEuroMP(B) ) )).
+
+fof(cEuropeanCountry_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & cEuropeanCountry(A) )
+ => cEuropeanCountry(B) ) )).
+
+fof(cPerson_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & cPerson(A) )
+ => cPerson(B) ) )).
+
+fof(cowlNothing_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & cowlNothing(A) )
+ => cowlNothing(B) ) )).
+
+fof(cowlThing_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & cowlThing(A) )
+ => cowlThing(B) ) )).
+
+fof(rhasEuroMP_substitution_1,axiom,
+ ( ! [A,B,C] :
+ ( ( A = B
+ & rhasEuroMP(A,C) )
+ => rhasEuroMP(B,C) ) )).
+
+fof(rhasEuroMP_substitution_2,axiom,
+ ( ! [A,B,C] :
+ ( ( A = B
+ & rhasEuroMP(C,A) )
+ => rhasEuroMP(C,B) ) )).
+
+fof(risEuroMPFrom_substitution_1,axiom,
+ ( ! [A,B,C] :
+ ( ( A = B
+ & risEuroMPFrom(A,C) )
+ => risEuroMPFrom(B,C) ) )).
+
+fof(risEuroMPFrom_substitution_2,axiom,
+ ( ! [A,B,C] :
+ ( ( A = B
+ & risEuroMPFrom(C,A) )
+ => risEuroMPFrom(C,B) ) )).
+
+fof(xsd_integer_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & xsd_integer(A) )
+ => xsd_integer(B) ) )).
+
+fof(xsd_string_substitution_1,axiom,
+ ( ! [A,B] :
+ ( ( A = B
+ & xsd_string(A) )
+ => xsd_string(B) ) )).
+
+%----Thing and Nothing
+fof(axiom_0,axiom,
+ ( ! [X] :
+ ( cowlThing(X)
+ & ~ cowlNothing(X) ) )).
+
+%----String and Integer disjoint
+fof(axiom_1,axiom,
+ ( ! [X] :
+ ( xsd_string(X)
+ <=> ~ xsd_integer(X) ) )).
+
+%----Enumeration cEUCountry
+fof(axiom_2,axiom,
+ ( ! [X] :
+ ( cEUCountry(X)
+ <=> ( X = iPT
+ | X = iBE
+ | X = iNL
+ | X = iES
+ | X = iFR
+ | X = iUK ) ) )).
+
+%----Equality cEuroMP
+fof(axiom_3,axiom,
+ ( ! [X] :
+ ( cEuroMP(X)
+ <=> ? [Y] :
+ ( risEuroMPFrom(X,Y)
+ & cowlThing(Y) ) ) )).
+
+%----Domain: rhasEuroMP
+fof(axiom_4,axiom,
+ ( ! [X,Y] :
+ ( rhasEuroMP(X,Y)
+ => cEUCountry(X) ) )).
+
+%----Inverse: risEuroMPFrom
+fof(axiom_5,axiom,
+ ( ! [X,Y] :
+ ( risEuroMPFrom(X,Y)
+ <=> rhasEuroMP(Y,X) ) )).
+
+%----iBE
+fof(axiom_6,axiom,
+ ( cEuropeanCountry(iBE) )).
+
+%----iES
+fof(axiom_7,axiom,
+ ( cEuropeanCountry(iES) )).
+
+%----iFR
+fof(axiom_8,axiom,
+ ( cEuropeanCountry(iFR) )).
+
+%----iKinnock
+fof(axiom_9,axiom,
+ ( cPerson(iKinnock) )).
+
+%----iKinnock
+fof(axiom_10,axiom,
+ ( ~ cEuroMP(iKinnock) )).
+
+%----iNL
+fof(axiom_11,axiom,
+ ( cEuropeanCountry(iNL) )).
+
+%----iPT
+fof(axiom_12,axiom,
+ ( cEuropeanCountry(iPT) )).
+
+%----iUK
+fof(axiom_13,axiom,
+ ( cEuropeanCountry(iUK) )).
+
+fof(axiom_14,axiom,
+ ( rhasEuroMP(iUK,iKinnock) )).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/MGT019+2.p b/test/regress/regress0/tptp/MGT019+2.p
new file mode 100644
index 000000000..fb2cd7f62
--- /dev/null
+++ b/test/regress/regress0/tptp/MGT019+2.p
@@ -0,0 +1,84 @@
+%--------------------------------------------------------------------------
+% File : MGT019+2 : TPTP v5.5.0. Released v2.0.0.
+% Domain : Management (Organisation Theory)
+% Problem : Growth rate of EPs exceeds that of FMs in stable environments
+% Version : [PM93] axioms.
+% English : The growth rate of efficent producers exceeds the growth rate
+% of first movers past a certain time in stable environments.
+
+% Refs : [PM93] Peli & Masuch (1993), The Logic of Propogation Strateg
+% : [PM94] Peli & Masuch (1994), The Logic of Propogation Strateg
+% : [PB+94] Peli et al. (1994), A Logical Approach to Formalizing
+% Source : [PM93]
+% Names : LEMMA 1 [PM93]
+% : L1 [PB+94]
+
+% Status : CounterSatisfiable
+% Rating : 0.00 v4.1.0, 0.20 v4.0.1, 0.00 v3.5.0, 0.33 v3.4.0, 0.00 v2.1.0
+% Syntax : Number of formulae : 5 ( 0 unit)
+% Number of atoms : 21 ( 1 equality)
+% Maximal formula depth : 8 ( 6 average)
+% Number of connectives : 17 ( 1 ~ ; 1 |; 8 &)
+% ( 0 <=>; 7 =>; 0 <=)
+% ( 0 <~>; 0 ~|; 0 ~&)
+% Number of predicates : 7 ( 0 propositional; 1-4 arity)
+% Number of functors : 5 ( 2 constant; 0-2 arity)
+% Number of variables : 11 ( 0 singleton; 9 !; 2 ?)
+% Maximal term depth : 2 ( 1 average)
+% SPC : FOF_CSA_RFO_SEQ
+
+% Comments : There is no MGT019+1 as Kamps did not send it to me.
+%--------------------------------------------------------------------------
+%----Subsitution axioms
+%----Problem axioms
+%----L2. The disbanding rate of first movers exceeds the disbanding
+%----rate of efficient producers.
+fof(l2,axiom,
+ ( ~ ( ! [E,T] :
+ ( ( environment(E)
+ & subpopulations(first_movers,efficient_producers,E,T) )
+ => greater(disbanding_rate(first_movers,T),disbanding_rate(efficient_producers,T)) ) ) )).
+
+%----If EP have lower disbanding rate and not lower founding rate than
+%----FM, then EP have higher growth rate.
+fof(mp_EP_lower_disbanding_rate,axiom,
+ ( ! [T] :
+ ( ( greater(disbanding_rate(first_movers,T),disbanding_rate(efficient_producers,T))
+ & greater_or_equal(founding_rate(efficient_producers,T),founding_rate(first_movers,T)) )
+ => greater(growth_rate(efficient_producers,T),growth_rate(first_movers,T)) ) )).
+
+%----MP. on "greater or equal to"
+fof(mp_greater_or_equal,axiom,
+ ( ! [X,Y] :
+ ( greater_or_equal(X,Y)
+ => ( greater(X,Y)
+ | X = Y ) ) )).
+
+%----A8. The founding rate of first movers does not exceed the founding
+%----rate of efficient producers past a certain point in a stable
+%----environment.
+fof(a8,hypothesis,
+ ( ! [E] :
+ ( ( environment(E)
+ & stable(E) )
+ => ? [To] :
+ ( in_environment(E,To)
+ & ! [T] :
+ ( ( subpopulations(first_movers,efficient_producers,E,T)
+ & greater_or_equal(T,To) )
+ => greater_or_equal(founding_rate(efficient_producers,T),founding_rate(first_movers,T)) ) ) ) )).
+
+%----GOAL: L1. The growth rate of efficient producers exceeds the growth
+%----rate of first movers past a certain time in stable environments.
+fof(prove_l1,conjecture,
+ ( ! [E] :
+ ( ( environment(E)
+ & stable(E) )
+ => ? [To] :
+ ( in_environment(E,To)
+ & ! [T] :
+ ( ( subpopulations(first_movers,efficient_producers,E,T)
+ & greater_or_equal(T,To) )
+ => greater(growth_rate(efficient_producers,T),growth_rate(first_movers,T)) ) ) ) )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/MGT031-1.p b/test/regress/regress0/tptp/MGT031-1.p
new file mode 100644
index 000000000..f5cd1937e
--- /dev/null
+++ b/test/regress/regress0/tptp/MGT031-1.p
@@ -0,0 +1,95 @@
+%--------------------------------------------------------------------------
+% File : MGT031-1 : TPTP v5.5.0. Released v2.4.0.
+% Domain : Management (Organisation Theory)
+% Problem : First movers appear first in an environment
+% Version : [PB+94] axioms : Reduced & Augmented > Complete.
+% English :
+
+% Refs : [PM93] Peli & Masuch (1993), The Logic of Propogation Strateg
+% : [PM94] Peli & Masuch (1994), The Logic of Propogation Strateg
+% : [Kam95] Kamps (1995), Email to G. Sutcliffe
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Rating : 0.00 v2.5.0, 0.17 v2.4.0
+% Syntax : Number of clauses : 15 ( 2 non-Horn; 3 unit; 15 RR)
+% Number of atoms : 38 ( 5 equality)
+% Maximal clause size : 5 ( 3 average)
+% Number of predicates : 6 ( 0 propositional; 1-3 arity)
+% Number of functors : 10 ( 6 constant; 0-2 arity)
+% Number of variables : 23 ( 0 singleton)
+% Maximal term depth : 3 ( 1 average)
+% SPC : CNF_SAT_RFO_EQU_NUE
+
+% Comments : Created with tptp2X -f tptp -t clausify:otter MGT031+1.p
+%--------------------------------------------------------------------------
+cnf(mp_positive_number_when_appear_20,axiom,
+ ( ~ environment(A)
+ | greater(number_of_organizations(e,appear(an_organisation,A)),zero) )).
+
+cnf(mp_number_mean_non_empty_21,axiom,
+ ( ~ environment(A)
+ | ~ greater(number_of_organizations(A,B),zero)
+ | subpopulation(sk1(B,A),A,B) )).
+
+cnf(mp_number_mean_non_empty_22,axiom,
+ ( ~ environment(A)
+ | ~ greater(number_of_organizations(A,B),zero)
+ | greater(cardinality_at_time(sk1(B,A),B),zero) )).
+
+cnf(mp_no_EP_before_appearance_23,axiom,
+ ( ~ environment(A)
+ | ~ in_environment(A,B)
+ | ~ greater(appear(efficient_producers,A),B)
+ | ~ greater(cardinality_at_time(efficient_producers,B),zero) )).
+
+cnf(mp_no_FM_before_appearance_24,axiom,
+ ( ~ environment(A)
+ | ~ in_environment(A,B)
+ | ~ greater(appear(first_movers,A),B)
+ | ~ greater(cardinality_at_time(first_movers,B),zero) )).
+
+cnf(mp_FM_not_precede_first_25,axiom,
+ ( ~ environment(A)
+ | greater_or_equal(appear(first_movers,A),appear(an_organisation,A)) )).
+
+cnf(mp_greater_transitivity_26,axiom,
+ ( ~ greater(A,B)
+ | ~ greater(B,C)
+ | greater(A,C) )).
+
+cnf(mp_greater_or_equal_27,axiom,
+ ( ~ greater_or_equal(A,B)
+ | greater(A,B)
+ | A = B )).
+
+cnf(mp_greater_or_equal_28,axiom,
+ ( ~ greater(A,B)
+ | greater_or_equal(A,B) )).
+
+cnf(mp_greater_or_equal_29,axiom,
+ ( A != B
+ | greater_or_equal(A,B) )).
+
+cnf(a9_30,hypothesis,
+ ( ~ environment(A)
+ | ~ subpopulation(B,A,C)
+ | ~ greater(cardinality_at_time(B,C),zero)
+ | B = efficient_producers
+ | B = first_movers )).
+
+cnf(a13_31,hypothesis,
+ ( ~ environment(A)
+ | greater(appear(efficient_producers,e),appear(first_movers,A)) )).
+
+cnf(prove_l13_32,negated_conjecture,
+ ( environment(sk2) )).
+
+cnf(prove_l13_33,negated_conjecture,
+ ( in_environment(sk2,appear(an_organisation,sk2)) )).
+
+cnf(prove_l13_34,negated_conjecture,
+ ( appear(an_organisation,sk2) != appear(first_movers,sk2) )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/MGT041-2.p b/test/regress/regress0/tptp/MGT041-2.p
new file mode 100644
index 000000000..a10a2f42d
--- /dev/null
+++ b/test/regress/regress0/tptp/MGT041-2.p
@@ -0,0 +1,61 @@
+%--------------------------------------------------------------------------
+% File : MGT041-2 : TPTP v5.5.0. Released v2.4.0.
+% Domain : Management (Organisation Theory)
+% Problem : There are non-FM and non-EP organisations
+% Version : [PM93] axioms.
+% English : There are non-first mover and non-efficient producers
+% organisations.
+
+% Refs : [PM93] Peli & Masuch (1993), The Logic of Propogation Strateg
+% : [PM94] Peli & Masuch (1994), The Logic of Propogation Strateg
+% : [Kam95] Kamps (1995), Email to G. Sutcliffe
+% Source : [TPTP]
+% Names :
+
+% Status : Unsatisfiable
+% Rating : 0.00 v2.4.0
+% Syntax : Number of clauses : 8 ( 1 non-Horn; 4 unit; 8 RR)
+% Number of atoms : 17 ( 0 equality)
+% Maximal clause size : 4 ( 2 average)
+% Number of predicates : 6 ( 0 propositional; 1-3 arity)
+% Number of functors : 4 ( 4 constant; 0-0 arity)
+% Number of variables : 8 ( 1 singleton)
+% Maximal term depth : 1 ( 1 average)
+% SPC : CNF_UNS_EPR
+
+% Comments : Created with tptp2X -f tptp -t clausify:otter MGT041+2.p
+%--------------------------------------------------------------------------
+cnf(mp_not_high_and_low_1,axiom,
+ ( ~ number_of_routines(A,B,low)
+ | ~ number_of_routines(A,B,high) )).
+
+cnf(a14_2,hypothesis,
+ ( ~ organisation_at_time(A,B)
+ | ~ efficient_producer(A)
+ | ~ founding_time(A,B)
+ | has_elaborated_routines(A,B) )).
+
+cnf(a15_3,hypothesis,
+ ( ~ organisation_at_time(A,B)
+ | ~ first_mover(A)
+ | ~ founding_time(A,B)
+ | number_of_routines(A,B,low) )).
+
+cnf(a16_4,hypothesis,
+ ( organisation_at_time(sk1,sk2) )).
+
+cnf(a16_5,hypothesis,
+ ( founding_time(sk1,sk2) )).
+
+cnf(a16_6,hypothesis,
+ ( number_of_routines(sk1,sk2,high) )).
+
+cnf(a16_7,hypothesis,
+ ( ~ has_elaborated_routines(sk1,sk2) )).
+
+cnf(prove_t10_8,negated_conjecture,
+ ( ~ organisation_at_time(A,B)
+ | first_mover(A)
+ | efficient_producer(A) )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/Makefile b/test/regress/regress0/tptp/Makefile
new file mode 100644
index 000000000..8c3909592
--- /dev/null
+++ b/test/regress/regress0/tptp/Makefile
@@ -0,0 +1,8 @@
+topdir = ../../../..
+srcdir = test/regress/regress0/tptp
+
+include $(topdir)/Makefile.subdir
+
+# synonyms for "check"
+.PHONY: test
+test: check
diff --git a/test/regress/regress0/tptp/Makefile.am b/test/regress/regress0/tptp/Makefile.am
new file mode 100644
index 000000000..e227e0bba
--- /dev/null
+++ b/test/regress/regress0/tptp/Makefile.am
@@ -0,0 +1,83 @@
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
+LOG_COMPILER = @srcdir@/../../run_regression
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+
+if AUTOMAKE_1_11
+# old-style (pre-automake 1.12) test harness
+TESTS_ENVIRONMENT = \
+ $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(AM_LOG_FLAGS) $(LOG_FLAGS)
+endif
+
+# escape the `=' in file names
+equals = =
+
+# These are run for all build profiles.
+# If a test shouldn't be run in e.g. competition mode,
+# put it below in "TESTS +="
+TESTS = \
+ tptp_parser.p \
+ tptp_parser2.p \
+ tptp_parser3.p \
+ tptp_parser4.p \
+ tptp_parser5.p \
+ tptp_parser6.p \
+ tptp_parser7.p \
+ tptp_parser8.p \
+ tptp_parser9.p \
+ tptp_parser10.p \
+ tff0.p \
+ tff0-arith.p \
+ ARI086$(equals)1.p \
+ BOO003-4.p \
+ DAT001$(equals)1.p \
+ KRS018+1.p \
+ KRS063+1.p \
+ MGT019+2.p \
+ MGT041-2.p \
+ PUZ131_1.p \
+ SYN000+1.p \
+ SYN000+2.p \
+ SYN000-1.p \
+ SYN000-2.p \
+ SYN000$(equals)2.p \
+ SYN000_1.p \
+ SYN000_2.p \
+ SYN075-1.p
+
+# axiom files required for the above tests
+TEST_DEPS_DIST = \
+ Axioms/BOO004-0.ax \
+ Axioms/SYN000_0.ax \
+ Axioms/SYN000-0.ax \
+ Axioms/SYN000+0.ax
+
+# these take too long at present
+EXTRA_DIST = $(TESTS) \
+ $(TEST_DEPS_DIST) \
+ BOO027-1.p \
+ MGT031-1.p \
+ NLP114-1.p \
+ SYN075+1.p
+
+#if CVC4_BUILD_PROFILE_COMPETITION
+#else
+#TESTS += \
+# error.cvc
+#endif
+#
+# and make sure to distribute it
+#EXTRA_DIST += \
+# error.cvc
+
+# synonyms for "check"
+.PHONY: regress regress0 test
+regress regress0 test: check
+
+# do nothing in this subdir
+.PHONY: regress1 regress2 regress3
+regress1 regress2 regress3:
diff --git a/test/regress/regress0/tptp/NLP114-1.p b/test/regress/regress0/tptp/NLP114-1.p
new file mode 100644
index 000000000..cf5bd272a
--- /dev/null
+++ b/test/regress/regress0/tptp/NLP114-1.p
@@ -0,0 +1,202 @@
+%--------------------------------------------------------------------------
+% File : NLP114-1 : TPTP v5.5.0. Released v2.4.0.
+% Domain : Natural Language Processing
+% Problem : An old dirty white Chevy, problem 1
+% Version : [Bos00b] axioms.
+% English : Eliminating logically equivalent interpretations in the statement
+% "An old dirty white chevy barrels down a lonely street in
+% hollywood."
+
+% Refs : [Bos00a] Bos (2000), DORIS: Discourse Oriented Representation a
+% [Bos00b] Bos (2000), Applied Theorem Proving - Natural Language
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Rating : 0.00 v2.4.0
+% Syntax : Number of clauses : 36 ( 16 non-Horn; 2 unit; 36 RR)
+% Number of atoms : 102 ( 0 equality)
+% Maximal clause size : 18 ( 3 average)
+% Number of predicates : 18 ( 1 propositional; 0-3 arity)
+% Number of functors : 11 ( 11 constant; 0-0 arity)
+% Number of variables : 11 ( 0 singleton)
+% Maximal term depth : 1 ( 1 average)
+% SPC : CNF_SAT_EPR
+
+% Comments : Created from NLP114+1.p using FLOTTER
+%--------------------------------------------------------------------------
+cnf(clause1,negated_conjecture,
+ ( actual_world(skc17) )).
+
+cnf(clause2,negated_conjecture,
+ ( actual_world(skc11) )).
+
+cnf(clause3,negated_conjecture,
+ ( ssSkC0
+ | city(skc17,skc20) )).
+
+cnf(clause4,negated_conjecture,
+ ( ssSkC0
+ | street(skc17,skc20) )).
+
+cnf(clause5,negated_conjecture,
+ ( ssSkC0
+ | lonely(skc17,skc20) )).
+
+cnf(clause6,negated_conjecture,
+ ( ssSkC0
+ | placename(skc17,skc21) )).
+
+cnf(clause7,negated_conjecture,
+ ( ssSkC0
+ | hollywood_placename(skc17,skc21) )).
+
+cnf(clause8,negated_conjecture,
+ ( ssSkC0
+ | event(skc17,skc18) )).
+
+cnf(clause9,negated_conjecture,
+ ( ssSkC0
+ | present(skc17,skc18) )).
+
+cnf(clause10,negated_conjecture,
+ ( ssSkC0
+ | barrel(skc17,skc18) )).
+
+cnf(clause11,negated_conjecture,
+ ( ssSkC0
+ | old(skc17,skc19) )).
+
+cnf(clause12,negated_conjecture,
+ ( ssSkC0
+ | dirty(skc17,skc19) )).
+
+cnf(clause13,negated_conjecture,
+ ( ssSkC0
+ | white(skc17,skc19) )).
+
+cnf(clause14,negated_conjecture,
+ ( ssSkC0
+ | chevy(skc17,skc19) )).
+
+cnf(clause15,negated_conjecture,
+ ( ~ ssSkC0
+ | lonely(skc11,skc16) )).
+
+cnf(clause16,negated_conjecture,
+ ( ~ ssSkC0
+ | street(skc11,skc16) )).
+
+cnf(clause17,negated_conjecture,
+ ( ~ ssSkC0
+ | barrel(skc11,skc12) )).
+
+cnf(clause18,negated_conjecture,
+ ( ~ ssSkC0
+ | present(skc11,skc12) )).
+
+cnf(clause19,negated_conjecture,
+ ( ~ ssSkC0
+ | event(skc11,skc12) )).
+
+cnf(clause20,negated_conjecture,
+ ( ~ ssSkC0
+ | hollywood_placename(skc11,skc14) )).
+
+cnf(clause21,negated_conjecture,
+ ( ~ ssSkC0
+ | placename(skc11,skc14) )).
+
+cnf(clause22,negated_conjecture,
+ ( ~ ssSkC0
+ | city(skc11,skc15) )).
+
+cnf(clause23,negated_conjecture,
+ ( ~ ssSkC0
+ | chevy(skc11,skc13) )).
+
+cnf(clause24,negated_conjecture,
+ ( ~ ssSkC0
+ | white(skc11,skc13) )).
+
+cnf(clause25,negated_conjecture,
+ ( ~ ssSkC0
+ | dirty(skc11,skc13) )).
+
+cnf(clause26,negated_conjecture,
+ ( ~ ssSkC0
+ | old(skc11,skc13) )).
+
+cnf(clause27,negated_conjecture,
+ ( ssSkC0
+ | down(skc17,skc18,skc20) )).
+
+cnf(clause28,negated_conjecture,
+ ( ssSkC0
+ | in(skc17,skc18,skc20) )).
+
+cnf(clause29,negated_conjecture,
+ ( ssSkC0
+ | of(skc17,skc21,skc20) )).
+
+cnf(clause30,negated_conjecture,
+ ( ssSkC0
+ | agent(skc17,skc18,skc19) )).
+
+cnf(clause31,negated_conjecture,
+ ( ~ ssSkC0
+ | down(skc11,skc12,skc16) )).
+
+cnf(clause32,negated_conjecture,
+ ( ~ ssSkC0
+ | in(skc11,skc12,skc15) )).
+
+cnf(clause33,negated_conjecture,
+ ( ~ ssSkC0
+ | of(skc11,skc14,skc15) )).
+
+cnf(clause34,negated_conjecture,
+ ( ~ ssSkC0
+ | agent(skc11,skc12,skc13) )).
+
+cnf(clause35,negated_conjecture,
+ ( ~ down(U,V,W)
+ | ~ lonely(U,W)
+ | ~ street(U,W)
+ | ~ barrel(U,V)
+ | ~ present(U,V)
+ | ~ event(U,V)
+ | ~ hollywood_placename(U,X)
+ | ~ placename(U,X)
+ | ~ in(U,V,Y)
+ | ~ city(U,Y)
+ | ~ of(U,X,Y)
+ | ~ chevy(U,Z)
+ | ~ white(U,Z)
+ | ~ dirty(U,Z)
+ | ~ old(U,Z)
+ | ~ agent(U,V,Z)
+ | ~ actual_world(U)
+ | ssSkC0 )).
+
+cnf(clause36,negated_conjecture,
+ ( ~ city(U,V)
+ | ~ street(U,V)
+ | ~ lonely(U,V)
+ | ~ down(U,W,V)
+ | ~ in(U,W,V)
+ | ~ placename(U,X)
+ | ~ hollywood_placename(U,X)
+ | ~ of(U,X,V)
+ | ~ event(U,W)
+ | ~ present(U,W)
+ | ~ barrel(U,W)
+ | ~ agent(U,W,Y)
+ | ~ old(U,Y)
+ | ~ dirty(U,Y)
+ | ~ white(U,Y)
+ | ~ chevy(U,Y)
+ | ~ actual_world(U)
+ | ~ ssSkC0 )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/PUZ131_1.p b/test/regress/regress0/tptp/PUZ131_1.p
new file mode 100644
index 000000000..b9e1c648b
--- /dev/null
+++ b/test/regress/regress0/tptp/PUZ131_1.p
@@ -0,0 +1,100 @@
+%------------------------------------------------------------------------------
+% File : PUZ131_1 : TPTP v5.5.0. Released v5.0.0.
+% Domain : Puzzles
+% Problem : Victor teaches Michael
+% Version : Especial.
+% English : Every student is enrolled in at least one course. Every professor
+% teaches at least one course. Every course has at least one student
+% enrolled. Every course has at least one professor teaching. The
+% coordinator of a course teaches the course. If a student is
+% enroled in a course then the student is taught by every professor
+% who teaches the course. Michael is enrolled in CSC410. Victor is
+% the coordinator of CSC410. Therefore, Michael is taught by Victor.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Theorem
+% Rating : 0.00 v5.0.0
+% Syntax : Number of formulae : 19 ( 14 unit; 10 type)
+% Number of atoms : 28 ( 1 equality)
+% Maximal formula depth : 6 ( 3 average)
+% Number of connectives : 2 ( 0 ~; 0 |; 0 &)
+% ( 0 <=>; 2 =>; 0 <=; 0 <~>)
+% ( 0 ~|; 0 ~&)
+% Number of type conns : 7 ( 4 >; 3 *; 0 +; 0 <<)
+% Number of predicates : 16 ( 12 propositional; 0-2 arity)
+% Number of functors : 4 ( 3 constant; 0-1 arity)
+% Number of variables : 12 ( 0 sgn; 8 !; 4 ?)
+% Maximal term depth : 2 ( 1 average)
+% SPC : TFF_THM_EQU_NAR
+
+% Comments :
+%------------------------------------------------------------------------------
+tff(student_type,type,(
+ student: $tType )).
+
+tff(professor_type,type,(
+ professor: $tType )).
+
+tff(course_type,type,(
+ course: $tType )).
+
+tff(michael_type,type,(
+ michael: student )).
+
+tff(victor_type,type,(
+ victor: professor )).
+
+tff(csc410_type,type,(
+ csc410: course )).
+
+tff(enrolled_type,type,(
+ enrolled: ( student * course ) > $o )).
+
+tff(teaches_type,type,(
+ teaches: ( professor * course ) > $o )).
+
+tff(taught_by_type,type,(
+ taughtby: ( student * professor ) > $o )).
+
+tff(coordinator_of_type,type,(
+ coordinatorof: course > professor )).
+
+tff(student_enrolled_axiom,axiom,(
+ ! [X: student] :
+ ? [Y: course] : enrolled(X,Y) )).
+
+tff(professor_teaches,axiom,(
+ ! [X: professor] :
+ ? [Y: course] : teaches(X,Y) )).
+
+tff(course_enrolled,axiom,(
+ ! [X: course] :
+ ? [Y: student] : enrolled(Y,X) )).
+
+tff(course_teaches,axiom,(
+ ! [X: course] :
+ ? [Y: professor] : teaches(Y,X) )).
+
+tff(coordinator_teaches,axiom,(
+ ! [X: course] : teaches(coordinatorof(X),X) )).
+
+tff(student_enrolled_taught,axiom,(
+ ! [X: student,Y: course] :
+ ( enrolled(X,Y)
+ => ! [Z: professor] :
+ ( teaches(Z,Y)
+ => taughtby(X,Z) ) ) )).
+
+tff(michael_enrolled_csc410_axiom,axiom,(
+ enrolled(michael,csc410) )).
+
+tff(victor_coordinator_csc410_axiom,axiom,(
+ coordinatorof(csc410) = victor )).
+
+tff(teaching_conjecture,conjecture,(
+ taughtby(michael,victor) )).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000+1.p b/test/regress/regress0/tptp/SYN000+1.p
new file mode 100644
index 000000000..682c11b69
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000+1.p
@@ -0,0 +1,99 @@
+%------------------------------------------------------------------------------
+% File : SYN000+1 : TPTP v5.5.0. Released v4.0.0.
+% Domain : Syntactic
+% Problem : Basic TPTP FOF syntax
+% Version : Biased.
+% English : Basic TPTP FOF syntax that you can't survive without parsing.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Theorem
+% Rating : 0.43 v5.5.0, 0.48 v5.4.0, 0.46 v5.3.0, 0.52 v5.2.0, 0.40 v5.1.0, 0.43 v5.0.0, 0.54 v4.1.0, 0.57 v4.0.1, 0.78 v4.0.0
+% Syntax : Number of formulae : 12 ( 5 unit)
+% Number of atoms : 31 ( 3 equality)
+% Maximal formula depth : 7 ( 4 average)
+% Number of connectives : 28 ( 9 ~; 10 |; 3 &)
+% ( 1 <=>; 3 =>; 1 <=)
+% ( 1 <~>; 0 ~|; 0 ~&)
+% Number of predicates : 16 ( 10 propositional; 0-3 arity)
+% Number of functors : 8 ( 5 constant; 0-3 arity)
+% Number of variables : 13 ( 0 sgn; 5 !; 8 ?)
+% Maximal term depth : 4 ( 2 average)
+% SPC : FOF_THM_RFO_SEQ
+
+% Comments :
+%------------------------------------------------------------------------------
+%----Propositional
+fof(propositional,axiom,
+ ( ( p0
+ & ~ q0 )
+ => ( r0
+ | ~ s0 ) )).
+
+%----First-order
+fof(first_order,axiom,(
+ ! [X] :
+ ( ( p(X)
+ | ~ q(X,a) )
+ => ? [Y,Z] :
+ ( r(X,f(Y),g(X,f(Y),Z))
+ & ~ s(f(f(f(b)))) ) ) )).
+
+%----Equality
+fof(equality,axiom,(
+ ? [Y] :
+ ! [X,Z] :
+ ( f(Y) = g(X,f(Y),Z)
+ | f(f(f(b))) != a
+ | X = f(Y) ) )).
+
+%----True and false
+fof(true_false,axiom,
+ ( $true
+ | $false )).
+
+%----Quoted symbols
+fof(single_quoted,axiom,
+ ( 'A proposition'
+ | 'A predicate'(a)
+ | p('A constant')
+ | p('A function'(a))
+ | p('A \'quoted \\ escape\'') )).
+
+%----Connectives - seen |, &, =>, ~ already
+fof(useful_connectives,axiom,(
+ ! [X] :
+ ( ( p(X)
+ <= ~ q(X,a) )
+ <=> ? [Y,Z] :
+ ( r(X,f(Y),g(X,f(Y),Z))
+ <~> ~ s(f(f(f(b)))) ) ) )).
+
+%----Annotated formula names
+fof(123,axiom,(
+ ! [X] :
+ ( ( p(X)
+ | ~ q(X,a) )
+ => ? [Y,Z] :
+ ( r(X,f(Y),g(X,f(Y),Z))
+ & ~ s(f(f(f(b)))) ) ) )).
+
+%----Roles
+fof(role_hypothesis,hypothesis,(
+ p(h) )).
+
+fof(role_conjecture,conjecture,(
+ ? [X] : p(X) )).
+
+%----Include directive
+include('Axioms/SYN000+0.ax').
+
+%----Comments
+/* This
+ is a block
+ comment.
+*/
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000+2.p b/test/regress/regress0/tptp/SYN000+2.p
new file mode 100644
index 000000000..8c6f2f9f9
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000+2.p
@@ -0,0 +1,127 @@
+%------------------------------------------------------------------------------
+% File : SYN000+2 : TPTP v5.5.0. Bugfixed v4.1.1.
+% Domain : Syntactic
+% Problem : Advanced TPTP FOF syntax
+% Version : Biased.
+% English : Advanced TPTP FOF syntax that you will encounter some time.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Rating : 0.50 v5.5.0, 0.67 v5.2.0, 1.00 v5.0.0
+% Syntax : Number of formulae : 20 ( 16 unit)
+% Number of atoms : 31 ( 2 equality)
+% Maximal formula depth : 7 ( 2 average)
+% Number of connectives : 13 ( 2 ~; 9 |; 0 &)
+% ( 0 <=>; 0 =>; 0 <=; 0 <~>)
+% ( 1 ~|; 1 ~&)
+% Number of predicates : 8 ( 3 propositional; 0-3 arity)
+% Number of functors : 22 ( 20 constant; 0-3 arity)
+% Number of variables : 8 ( 0 sgn; 8 !; 0 ?)
+% Maximal term depth : 2 ( 1 average)
+% Arithmetic symbols : 12 ( 0 pred; 0 func; 12 numbers)
+% SPC : FOF_SAT_RFO_SEQ
+
+% Comments :
+% Bugfixes : v4.0.1 - Added more numbers, particularly rationals.
+% : v4.1.1 - Removed rationals with negative denominators.
+%------------------------------------------------------------------------------
+%----Quoted symbols
+fof(distinct_object,axiom,(
+ "An Apple" != "A \"Microsoft \\ escape\"" )).
+
+%----Numbers
+fof(integers,axiom,
+ ( p(12)
+ | p(-12) )).
+
+fof(rationals,axiom,
+ ( p(123/456)
+ | p(-123/456)
+ | p(+123/456) )).
+
+fof(reals,axiom,
+ ( p(123.456 )
+ | p(-123.456 )
+ | p(123.456E789 )
+ | p(123.456e789 )
+ | p(-123.456E789 )
+ | p(123.456E-789 )
+ | p(-123.456E-789 ) )).
+
+%----Connectives - seen |, &, =>, ~ already
+fof(never_used_connectives,axiom,(
+ ! [X] :
+ ( ( p(X)
+ ~| ~ q(X,a) )
+ ~& p(X) ) )).
+
+%----Roles
+fof(role_definition,definition,(
+ ! [X] : f(d) = f(X) )).
+
+fof(role_assumption,assumption,(
+ p(a) )).
+
+fof(role_lemma,lemma,(
+ p(l) )).
+
+fof(role_theorem,theorem,(
+ p(t) )).
+
+fof(role_unknown,unknown,(
+ p(u) )).
+
+%----Selective include directive
+include('Axioms/SYN000+0.ax',[ia1,ia3]).
+
+%----Source
+fof(source_unknown,axiom,(
+ ! [X] : p(X) ),
+ unknown).
+
+fof(source,axiom,(
+ ! [X] : p(X) ),
+ file('SYN000-1.p')).
+
+fof(source_name,axiom,(
+ ! [X] : p(X) ),
+ file('SYN000-1.p',source_unknown)).
+
+fof(source_copy,axiom,(
+ ! [X] : p(X) ),
+ source_unknown).
+
+fof(source_introduced_assumption,axiom,(
+ ! [X] : p(X) ),
+ introduced(assumption,[from,the,world])).
+
+fof(source_inference,plain,(
+ p(a) ),
+ inference(magic,
+ [status(thm),assumptions([source_introduced_assumption])],
+ [theory(equality),source_unknown])).
+
+fof(source_inference_with_bind,plain,(
+ p(a) ),
+ inference(magic,
+ [status(thm)],
+ [theory(equality),source_unknown:[bind(X,$fot(a))]])).
+
+%----Useful info
+fof(useful_info,axiom,(
+ ! [X] : p(X) ),
+ unknown,
+ [simple,
+ prolog(like,Data,[nested,12.2]),
+ AVariable,
+ 12.2,
+ "A distinct object",
+ $fof(p(X) | ~ q(X,a) | r(X,f(Y),g(X,f(Y),Z)) | ~ s(f(f(f(b))))),
+ data(name):[colon,list,2],
+ [simple,prolog(like,Data,[nested,12.2]),AVariable,12.2]
+ ]).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000-1.p b/test/regress/regress0/tptp/SYN000-1.p
new file mode 100644
index 000000000..b6a68ec95
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000-1.p
@@ -0,0 +1,83 @@
+%------------------------------------------------------------------------------
+% File : SYN000-1 : TPTP v5.5.0. Released v4.0.0.
+% Domain : Syntactic
+% Problem : Basic TPTP CNF syntax
+% Version : Biased.
+% English : Basic TPTP CNF syntax that you can't survive without parsing.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Unsatisfiable
+% Rating : 0.50 v5.4.0, 0.55 v5.3.0, 0.56 v5.2.0, 0.62 v5.1.0, 0.65 v5.0.0, 0.64 v4.1.0, 0.62 v4.0.1, 0.64 v4.0.0
+% Syntax : Number of clauses : 11 ( 6 non-Horn; 5 unit; 7 RR)
+% Number of atoms : 27 ( 3 equality)
+% Maximal clause size : 5 ( 2 average)
+% Number of predicates : 16 ( 10 propositional; 0-3 arity)
+% Number of functors : 8 ( 5 constant; 0-3 arity)
+% Number of variables : 11 ( 5 singleton)
+% Maximal term depth : 4 ( 2 average)
+% SPC : CNF_UNS_RFO_SEQ_NHN
+
+% Comments :
+%------------------------------------------------------------------------------
+%----Propositional
+cnf(propositional,axiom,
+ ( p0
+ | ~ q0
+ | r0
+ | ~ s0 )).
+
+%----First-order
+cnf(first_order,axiom,
+ ( p(X)
+ | ~ q(X,a)
+ | r(X,f(Y),g(X,f(Y),Z))
+ | ~ s(f(f(f(b)))) )).
+
+%----Equality
+cnf(equality,axiom,
+ ( f(Y) = g(X,f(Y),Z)
+ | f(f(f(b))) != a
+ | X = f(Y) )).
+
+%----True and false
+cnf(true_false,axiom,
+ ( $true
+ | $false )).
+
+%----Quoted symbols
+cnf(single_quoted,axiom,
+ ( 'A proposition'
+ | 'A predicate'(Y)
+ | p('A constant')
+ | p('A function'(a))
+ | p('A \'quoted \\ escape\'') )).
+
+%----Connectives - seen them all already
+
+%----Annotated formula names
+cnf(123,axiom,
+ ( p(X)
+ | ~ q(X,a)
+ | r(X,f(Y),g(X,f(Y),Z))
+ | ~ s(f(f(f(b)))) )).
+
+%----Roles - seen axiom already
+cnf(role_hypothesis,hypothesis,
+ p(h)).
+
+cnf(role_negated_conjecture,negated_conjecture,
+ ~ p(X)).
+
+%----Include directive
+include('Axioms/SYN000-0.ax').
+
+%----Comments
+/* This
+ is a block
+ comment.
+*/
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000-2.p b/test/regress/regress0/tptp/SYN000-2.p
new file mode 100644
index 000000000..0c6c0b59f
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000-2.p
@@ -0,0 +1,117 @@
+%------------------------------------------------------------------------------
+% File : SYN000-2 : TPTP v5.5.0. Bugfixed v4.1.1.
+% Domain : Syntactic
+% Problem : Advanced TPTP CNF syntax
+% Version : Biased.
+% English : Advanced TPTP CNF syntax that you will encounter some time.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Rating : 1.00 v5.4.0, 0.90 v5.3.0, 0.89 v5.2.0, 0.90 v5.0.0
+% Syntax : Number of clauses : 19 ( 3 non-Horn; 16 unit; 12 RR)
+% Number of atoms : 28 ( 2 equality)
+% Maximal clause size : 7 ( 1 average)
+% Number of predicates : 8 ( 3 propositional; 0-3 arity)
+% Number of functors : 22 ( 20 constant; 0-3 arity)
+% Number of variables : 7 ( 7 singleton)
+% Maximal term depth : 2 ( 1 average)
+% Arithmetic symbols : 12 ( 0 pred; 0 func; 12 numbers)
+% SPC : CNF_SAT_RFO_EQU_NUE
+
+% Comments :
+% Bugfixes : v4.0.1 - Added more numbers, particularly rationals.
+% : v4.1.1 - Removed rationals with negative denominators.
+%------------------------------------------------------------------------------
+%----Quoted symbols
+cnf(distinct_object,axiom,
+ ( "An Apple" != "A \"Microsoft \\ escape\"" )).
+
+%----Numbers
+cnf(integers,axiom,
+ ( p(12)
+ | p(-12) )).
+
+cnf(rationals,axiom,
+ ( p(123/456)
+ | p(-123/456)
+ | p(+123/456) )).
+
+cnf(reals,axiom,
+ ( p(123.456 )
+ | p(-123.456 )
+ | p(123.456E789 )
+ | p(123.456e789 )
+ | p(-123.456E789 )
+ | p(123.456E-789 )
+ | p(-123.456E-789 ) )).
+
+%----Roles - seen axiom already
+cnf(role_definition,definition,
+ f(d) = f(X) ).
+
+cnf(role_assumption,assumption,
+ p(a) ).
+
+cnf(role_lemma,lemma,
+ p(l) ).
+
+cnf(role_theorem,theorem,
+ p(t) ).
+
+cnf(role_unknown,unknown,
+ p(u) ).
+
+%----Selective include directive
+include('Axioms/SYN000-0.ax',[ia1,ia3]).
+
+%----Source
+cnf(source_unknown,axiom,
+ p(X),
+ unknown).
+
+cnf(source,axiom,
+ p(X),
+ file('SYN000-1.p')).
+
+cnf(source_name,axiom,
+ p(X),
+ file('SYN000-1.p',source_unknown)).
+
+cnf(source_copy,axiom,
+ p(X),
+ source_unknown).
+
+cnf(source_introduced_assumption,axiom,
+ p(X),
+ introduced(assumption,[from,the,world])).
+
+cnf(source_inference,plain,
+ p(a),
+ inference(magic,
+ [status(thm),assumptions([source_introduced_assumption])],
+ [theory(equality),source_unknown]) ).
+
+cnf(source_inference_with_bind,plain,
+ p(a),
+ inference(magic,
+ [status(thm)],
+ [theory(equality),source_unknown:[bind(X,$fot(a))]]) ).
+
+%----Useful info
+cnf(useful_info,axiom,
+ p(X),
+ unknown,
+ [simple,
+ prolog(like,Data,[nested,12.2]),
+ AVariable,
+ 12.2,
+ "A distinct object",
+ $cnf(p(X) | ~q(X,a) | r(X,f(Y),g(X,f(Y),Z)) | ~ s(f(f(f(b))))),
+ data(name):[colon,list,2],
+ [simple,prolog(like,Data,[nested,12.2]),AVariable,12.2]
+ ]).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000=2.p b/test/regress/regress0/tptp/SYN000=2.p
new file mode 100644
index 000000000..802613f4b
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000=2.p
@@ -0,0 +1,309 @@
+%------------------------------------------------------------------------------
+% File : SYN000=2 : TPTP v5.5.0. Bugfixed v5.5.1.
+% Domain : Syntactic
+% Problem : TF0 syntax with arithmetic
+% Version : Biased.
+% English :
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Theorem
+% Rating : ? v5.5.1
+% Syntax : Number of formulae : 83 ( 73 unit; 6 type)
+% Number of atoms : 100 ( 4 equality)
+% Maximal formula depth : 7 ( 1 average)
+% Number of connectives : 14 ( 0 ~; 10 |; 1 &)
+% ( 0 <=>; 3 =>; 0 <=; 0 <~>)
+% ( 0 ~|; 0 ~&)
+% Number of type conns : 3 ( 3 >; 0 *; 0 +; 0 <<)
+% Number of predicates : 20 ( 10 propositional; 0-2 arity)
+% Number of functors : 41 ( 24 constant; 0-2 arity)
+% Number of variables : 14 ( 1 sgn; 3 !; 11 ?)
+% Maximal term depth : 3 ( 1 average)
+% Arithmetic symbols : 37 ( 9 pred; 7 func; 21 numbers)
+% SPC : TF0_THM_EQU_ARI
+
+% Comments :
+% Bugfixes : v5.5.1 - Removed $evaleq.
+%------------------------------------------------------------------------------
+%----Types for what follows
+tff(p_int_type,type,(
+ p_int: $int > $o )).
+
+tff(p_rat_type,type,(
+ p_rat: $rat > $o )).
+
+tff(p_real_type,type,(
+ p_real: $real > $o )).
+
+tff(a_int,type,(
+ a_int: $int )).
+
+tff(a_rat,type,(
+ a_rat: $rat )).
+
+tff(a_real,type,(
+ a_real: $real )).
+
+%----Numbers
+tff(integers,axiom,
+ ( p_int(123)
+ | p_int(-123) )).
+
+tff(rationals,axiom,
+ ( p_rat(123/456)
+ | p_rat(-123/456)
+ | p_rat(123/456) )).
+
+tff(reals,axiom,
+ ( p_real(123.456)
+ | p_real(-123.456)
+ | p_real(123.456E78)
+ | p_real(123.456e78)
+ | p_real(-123.456E78)
+ | p_real(123.456E-78)
+ | p_real(-123.456E-78) )).
+
+%----Variables
+tff(variables_int,axiom,(
+ ! [X: $int] :
+ ? [Y: $int] :
+ ( p_int(X)
+ => p_int(Y) ) )).
+
+tff(variables_rat,axiom,(
+ ! [X: $rat] :
+ ? [Y: $rat] :
+ ( p_rat(X)
+ => p_rat(Y) ) )).
+
+tff(variables_real,axiom,(
+ ! [X: $real] :
+ ? [Y: $real] :
+ ( p_real(X)
+ => p_real(Y) ) )).
+
+%----Arithmetic relations
+tff(less_int,axiom,(
+ $less(a_int,3) )).
+
+tff(less_rat,axiom,(
+ $less(a_rat,3/9) )).
+
+tff(less_real,axiom,(
+ $less(a_real,3.3) )).
+
+tff(lesseq_int,axiom,(
+ $lesseq(a_int,3) )).
+
+tff(lesseq_rat,axiom,(
+ $lesseq(a_rat,3/9) )).
+
+tff(lesseq_real,axiom,(
+ $lesseq(a_real,3.3) )).
+
+tff(greater_int,axiom,(
+ $greater(a_int,-3) )).
+
+tff(greater_rat,axiom,(
+ $greater(a_rat,-3/9) )).
+
+tff(greater_real,axiom,(
+ $greater(a_real,-3.3) )).
+
+tff(greatereq_int,axiom,(
+ $greatereq(a_int,-3) )).
+
+tff(greatereq_rat,axiom,(
+ $greatereq(a_rat,-3/9) )).
+
+tff(greatereq_real,axiom,(
+ $greatereq(a_real,-3.3) )).
+
+tff(equal_int,axiom,(
+ a_int = 0 )).
+
+tff(equal_rat,axiom,(
+ a_rat = 0/1 )).
+
+tff(equal_real,axiom,(
+ a_real = 0.0 )).
+
+%----Arithmetic functions
+tff(uminus_int,axiom,(
+ p_int($uminus(3)) )).
+
+tff(uminus_rat,axiom,(
+ p_rat($uminus(3/9)) )).
+
+tff(uminus_real,axiom,(
+ p_real($uminus(3.3)) )).
+
+tff(sum_int,axiom,(
+ p_int($sum(3,3)) )).
+
+tff(sum_rat,axiom,(
+ p_rat($sum(3/9,3/9)) )).
+
+tff(sum_real,axiom,(
+ p_real($sum(3.3,3.3)) )).
+
+tff(difference_int,axiom,(
+ p_int($difference(3,3)) )).
+
+tff(difference_rat,axiom,(
+ p_rat($difference(3/9,3/9)) )).
+
+tff(difference_real,axiom,(
+ p_real($difference(3.3,3.3)) )).
+
+tff(product_int,axiom,(
+ p_int($product(3,3)) )).
+
+tff(product_rat,axiom,(
+ p_rat($product(3/9,3/9)) )).
+
+tff(product_real,axiom,(
+ p_real($product(3.3,3.3)) )).
+
+tff(quotient_rat,axiom,(
+ p_rat($quotient(3/9,3/9)) )).
+
+tff(quotient_real,axiom,(
+ p_real($quotient(3.3,3.3)) )).
+
+tff(quotient_e_int,axiom,(
+ p_int($quotient_e(3,3)) )).
+
+tff(quotient_e_rat,axiom,(
+ p_rat($quotient_e(3/9,3/9)) )).
+
+tff(quotient_e_real,axiom,(
+ p_real($quotient_e(3.3,3.3)) )).
+
+tff(quotient_t_int,axiom,(
+ p_int($quotient_t(3,3)) )).
+
+tff(quotient_t_rat,axiom,(
+ p_rat($quotient_t(3/9,3/9)) )).
+
+tff(quotient_t_real,axiom,(
+ p_real($quotient_t(3.3,3.3)) )).
+
+tff(quotient_f_int,axiom,(
+ p_int($quotient_f(3,3)) )).
+
+tff(quotient_f_rat,axiom,(
+ p_rat($quotient_f(3/9,3/9)) )).
+
+tff(quotient_f_real,axiom,(
+ p_real($quotient_f(3.3,3.3)) )).
+
+tff(remainder_e_int,axiom,(
+ p_int($remainder_e(3,3)) )).
+
+tff(remainder_e_rat,axiom,(
+ p_rat($remainder_e(3/9,3/9)) )).
+
+tff(remainder_e_real,axiom,(
+ p_real($remainder_e(3.3,3.3)) )).
+
+tff(remainder_t_int,axiom,(
+ p_int($remainder_t(3,3)) )).
+
+tff(remainder_t_rat,axiom,(
+ p_rat($remainder_t(3/9,3/9)) )).
+
+tff(remainder_t_real,axiom,(
+ p_real($remainder_t(3.3,3.3)) )).
+
+tff(remainder_f_int,axiom,(
+ p_int($remainder_f(3,3)) )).
+
+tff(remainder_f_rat,axiom,(
+ p_rat($remainder_f(3/9,3/9)) )).
+
+tff(remainder_f_real,axiom,(
+ p_real($remainder_f(3.3,3.3)) )).
+
+tff(floor_int,axiom,(
+ p_int($floor(3)) )).
+
+tff(floor_rat,axiom,(
+ p_rat($floor(3/9)) )).
+
+tff(floor_int,axiom,(
+ p_real($floor(3.3)) )).
+
+tff(ceiling_int,axiom,(
+ p_int($ceiling(3)) )).
+
+tff(ceiling_rat,axiom,(
+ p_rat($ceiling(3/9)) )).
+
+tff(ceiling_int,axiom,(
+ p_real($ceiling(3.3)) )).
+
+tff(truncate_int,axiom,(
+ p_int($truncate(3)) )).
+
+tff(truncate_rat,axiom,(
+ p_rat($truncate(3/9)) )).
+
+tff(truncate_int,axiom,(
+ p_real($truncate(3.3)) )).
+
+%----Recognizing numbers
+tff(is_int_int,axiom,(
+ ? [X: $int] : $is_int(X) )).
+
+tff(is_int_rat,axiom,(
+ ? [X: $rat] : $is_int(X) )).
+
+tff(is_int_real,axiom,(
+ ? [X: $real] : $is_int(X) )).
+
+tff(is_rat_rat,axiom,(
+ ? [X: $rat] : $is_rat(X) )).
+
+tff(is_rat_real,axiom,(
+ ? [X: $real] : $is_rat(X) )).
+
+%----Coercion
+tff(to_int_int,axiom,(
+ p_int($to_int(3)) )).
+
+tff(to_int_rat,axiom,(
+ p_int($to_int(3/9)) )).
+
+tff(to_int_real,axiom,(
+ p_int($to_int(3.3)) )).
+
+tff(to_rat_int,axiom,(
+ p_rat($to_rat(3)) )).
+
+tff(to_rat_rat,axiom,(
+ p_rat($to_rat(3/9)) )).
+
+tff(to_rat_real,axiom,(
+ p_rat($to_rat(3.3)) )).
+
+tff(to_real_int,axiom,(
+ p_real($to_real(3)) )).
+
+tff(to_real_rat,axiom,(
+ p_real($to_real(3/9)) )).
+
+tff(to_real_real,axiom,(
+ p_real($to_real(3.3)) )).
+
+%----A conjecture to prove
+tff(mixed,conjecture,(
+ ? [X: $int,Y: $rat,Z: $real] :
+ ( Y = $to_rat($sum(X,2))
+ & ( $less($to_int(Y),3)
+ | $greater($to_real(Y),3.3) ) ) )).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000_1.p b/test/regress/regress0/tptp/SYN000_1.p
new file mode 100644
index 000000000..ed683c070
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000_1.p
@@ -0,0 +1,170 @@
+%------------------------------------------------------------------------------
+% File : SYN000_1 : TPTP v5.5.0. Released v5.0.0.
+% Domain : Syntactic
+% Problem : Basic TPTP TFF syntax without arithmetic
+% Version : Biased.
+% English : Basic TPTP TFF syntax that you can't survive without parsing.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Theorem
+% Rating : 0.40 v5.5.0, 0.25 v5.4.0, 0.33 v5.2.0, 0.67 v5.0.0
+% Syntax : Number of formulae : 38 ( 21 unit; 25 type)
+% Number of atoms : 74 ( 3 equality)
+% Maximal formula depth : 7 ( 3 average)
+% Number of connectives : 28 ( 9 ~; 10 |; 3 &)
+% ( 1 <=>; 3 =>; 1 <=; 1 <~>)
+% ( 0 ~|; 0 ~&)
+% Number of type conns : 17 ( 10 >; 7 *; 0 +; 0 <<)
+% Number of predicates : 37 ( 30 propositional; 0-3 arity)
+% Number of functors : 10 ( 6 constant; 0-3 arity)
+% Number of variables : 14 ( 1 sgn; 6 !; 8 ?)
+% Maximal term depth : 4 ( 2 average)
+% SPC : TFF_THM_EQU_NAR
+
+% Comments :
+%------------------------------------------------------------------------------
+%----Propositional
+tff(p0_type,type,(
+ p0: $o )).
+
+tff(q0_type,type,(
+ q0: $o )).
+
+tff(r0_type,type,(
+ r0: $o )).
+
+tff(s0_type,type,(
+ s0: $o )).
+
+tff(propositional,axiom,
+ ( ( p0
+ & ~ q0 )
+ => ( r0
+ | ~ s0 ) )).
+
+%----First-order
+tff(a_type,type,(
+ a: $i )).
+
+tff(b_type,type,(
+ b: $i )).
+
+tff(h_type,type,(
+ h: $i )).
+
+tff(f_type,type,(
+ f: $i > $i )).
+
+tff(g_type,type,(
+ g: ( $i * $i * $i ) > $i )).
+
+tff(p_type,type,(
+ p: $i > $o )).
+
+tff(q_type,type,(
+ q: ( $i * $i ) > $o )).
+
+tff(r_type,type,(
+ r: ( $i * $i * $i ) > $o )).
+
+tff(s_type,type,(
+ s: $i > $o )).
+
+tff(first_order,axiom,(
+ ! [X: $i] :
+ ( ( p(X)
+ | ~ q(X,a) )
+ => ? [Y: $i,Z: $i] :
+ ( r(X,f(Y),g(X,f(Y),Z))
+ & ~ s(f(f(f(b)))) ) ) )).
+
+%----Equality
+tff(equality,axiom,(
+ ? [Y: $i] :
+ ! [X: $i,Z: $i] :
+ ( f(Y) = g(X,f(Y),Z)
+ | f(f(f(b))) != a
+ | X = f(Y) ) )).
+
+%----True and false
+tff(true_false,axiom,
+ ( $true
+ | $false )).
+
+tff(quoted_proposition_type,type,(
+ 'A proposition': $o )).
+
+tff(quoted_predicate_type,type,(
+ 'A predicate': $i > $o )).
+
+tff(quoted_constant_type,type,(
+ 'A constant': $i )).
+
+tff(quoted_function_type,type,(
+ 'A function': $i > $i )).
+
+tff(quoted_escape_type,type,(
+ 'A \'quoted \\ escape\'': $i )).
+
+%----Quoted symbols
+tff(single_quoted,axiom,
+ ( 'A proposition'
+ | 'A predicate'(a)
+ | p('A constant')
+ | p('A function'(a))
+ | p('A \'quoted \\ escape\'') )).
+
+%----Connectives - seen |, &, =>, ~ already
+tff(useful_connectives,axiom,(
+ ! [X: $i] :
+ ( ( p(X)
+ <= ~ q(X,a) )
+ <=> ? [Y: $i,Z: $i] :
+ ( r(X,f(Y),g(X,f(Y),Z))
+ <~> ~ s(f(f(f(b)))) ) ) )).
+
+%----New types
+tff(new_type,type,(
+ new: $tType )).
+
+tff(newc_type,type,(
+ newc: new )).
+
+tff(newf_type,type,(
+ newf: ( new * $i ) > new )).
+
+tff(newp_type,type,(
+ newp: ( new * $i ) > $o )).
+
+tff(new_axiom,axiom,(
+ ! [X: new] : newp(newf(newc,a),a) )).
+
+%----Annotated formula names
+tff(123,axiom,(
+ ! [X: $i] :
+ ( ( p(X)
+ | ~ q(X,a) )
+ => ? [Y: $i,Z: $i] :
+ ( r(X,f(Y),g(X,f(Y),Z))
+ & ~ s(f(f(f(b)))) ) ) )).
+
+%----Roles
+tff(role_hypothesis,hypothesis,(
+ p(h) )).
+
+tff(role_conjecture,conjecture,(
+ ? [X: $i] : p(X) )).
+
+%----Include directive
+include('Axioms/SYN000_0.ax').
+
+%----Comments
+/* This
+ is a block
+ comment.
+*/
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN000_2.p b/test/regress/regress0/tptp/SYN000_2.p
new file mode 100644
index 000000000..ece5fa6b1
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN000_2.p
@@ -0,0 +1,135 @@
+%------------------------------------------------------------------------------
+% File : SYN000_2 : TPTP v5.5.0. Bugfixed v5.5.1.
+% Domain : Syntactic
+% Problem : Advanced TPTP TF0 syntax without arithmetic
+% Version : Biased.
+% English : Advanced TPTP TF0 syntax that you will encounter some time.
+
+% Refs :
+% Source : [TPTP]
+% Names :
+
+% Status : Satisfiable
+% Rating : ? v5.5.1
+% Syntax : Number of formulae : 26 ( 18 unit; 7 type)
+% Number of atoms : 42 ( 2 equality)
+% Maximal formula depth : 5 ( 2 average)
+% Number of connectives : 6 ( 2 ~; 0 |; 1 &)
+% ( 1 <=>; 0 =>; 0 <=; 0 <~>)
+% ( 1 ~|; 1 ~&)
+% Number of type conns : 9 ( 5 >; 4 *; 0 +; 0 <<)
+% Number of predicates : 14 ( 11 propositional; 0-2 arity)
+% Number of functors : 6 ( 4 constant; 0-2 arity)
+% Number of variables : 18 ( 0 sgn; 13 !; 1 ?)
+% Maximal term depth : 2 ( 1 average)
+% SPC : TF0_SAT_EQU_NAR
+
+% Comments :
+% Bugfixes : v5.5.1 - Fixed let_binders.
+%------------------------------------------------------------------------------
+%----Quoted symbols
+tff(distinct_object,axiom,(
+ "An Apple" != "A \"Microsoft \\ escape\"" )).
+
+%----Types for stuff below
+tff(a_type,type,(
+ a: $i )).
+
+tff(b_type,type,(
+ b: $i )).
+
+tff(f_type,type,(
+ f: $i > $i )).
+
+tff(g_type,type,(
+ g: ( $i * $i ) > $i )).
+
+tff(h_type,type,(
+ h: ( $i * $i * $i ) > $i )).
+
+tff(p_type,type,(
+ p: $i > $o )).
+
+tff(q_type,type,(
+ q: ( $i * $i ) > $o )).
+
+%----Conditional constructs
+tff(conditionals,axiom,(
+ ! [Z: $i] :
+ $ite_f(
+ ? [X: $i] : p(X)
+ , ! [X: $i] : q(X,X)
+ , q(Z,$ite_t(! [X: $i] : p(X), f(a), f(Z))) ) )).
+
+%----Let binders
+tff(let_binders,axiom,(
+ ! [X: $i] :
+ $let_ff(
+ ! [Y1: $i,Y2: $i] :
+ ( q(Y1,Y2)
+ <=> p(Y1) )
+ , ( q($let_tt(! [Z1: $i] : f(Z1) = g(Z1,b), f(a)),X)
+ & p($let_ft(! [Y3: $i] : ! [Y4: $i] : ( q(Y3,Y4) <=> $ite_f(Y3 = Y4, q(a,a), q(Y3,Y4) ) ), $ite_t(q(b,b), f(a), f(X)))) ) ) )).
+
+%----Rare connectives
+tff(never_used_connectives,axiom,(
+ ! [X: $i] :
+ ( ( p(X)
+ ~| ~ q(X,a) )
+ ~& p(X) ) )).
+
+%----Roles
+tff(role_definition,definition,(
+ ! [X: $i] : f(a) = f(X) )).
+
+tff(role_assumption,assumption,(
+ p(a) )).
+
+tff(role_lemma,lemma,(
+ p(a) )).
+
+tff(role_theorem,theorem,(
+ p(a) )).
+
+tff(role_unknown,unknown,(
+ p(a) )).
+
+%----Selective include directive
+include('Axioms/SYN000_0.ax',[ia1,ia3]).
+
+%----Source
+tff(source_unknown,axiom,(
+ ! [X: $i] : p(X) ),
+ unknown).
+
+tff(source,axiom,(
+ ! [X: $i] : p(X) ),
+ file('SYN000-1.p')).
+
+tff(source_name,axiom,(
+ ! [X: $i] : p(X) ),
+ file('SYN000-1.p',source_unknown)).
+
+tff(source_copy,axiom,(
+ ! [X: $i] : p(X) ),
+ source_unknown).
+
+tff(source_introduced_assumption,axiom,(
+ ! [X: $i] : p(X) ),
+ introduced(assumption,[from,the,world])).
+
+tff(source_inference,plain,(
+ p(a) ),
+ inference(magic,[status(thm),assumptions([source_introduced_assumption])],[theory(equality),source_unknown])).
+
+tff(source_inference_with_bind,plain,(
+ p(a) ),
+ inference(magic,[status(thm)],[theory(equality),source_unknown:[bind(X,$fot(a))]])).
+
+%----Useful info
+tff(useful_info,axiom,(
+ ! [X: $i] : p(X) ),
+ unknown,
+ [simple,prolog(like,Data,[nested,12.2]),AVariable,12.2,"A distinct object",$tff(p(X) | ~ q(X,a)),data(name):[colon,list,2],[simple,prolog(like,Data,[nested,12.2]),AVariable,12.2]]).
+
+%------------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN075+1.p b/test/regress/regress0/tptp/SYN075+1.p
new file mode 100644
index 000000000..7ef40217c
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN075+1.p
@@ -0,0 +1,46 @@
+%--------------------------------------------------------------------------
+% File : SYN075+1 : TPTP v5.5.0. Released v2.0.0.
+% Domain : Syntactic
+% Problem : Pelletier Problem 52
+% Version : Especial.
+% English :
+
+% Refs : [Pel86] Pelletier (1986), Seventy-five Problems for Testing Au
+% : [Hah94] Haehnle (1994), Email to G. Sutcliffe
+% Source : [Hah94]
+% Names : Pelletier 52 [Pel86]
+
+% Status : Theorem
+% Rating : 0.22 v5.5.0, 0.15 v5.4.0, 0.18 v5.3.0, 0.26 v5.2.0, 0.05 v5.0.0, 0.21 v4.1.0, 0.17 v4.0.1, 0.22 v4.0.0, 0.21 v3.7.0, 0.00 v3.3.0, 0.11 v3.2.0, 0.33 v3.1.0, 0.17 v2.7.0, 0.00 v2.5.0, 0.33 v2.4.0, 0.33 v2.2.1, 0.00 v2.1.0
+% Syntax : Number of formulae : 2 ( 0 unit)
+% Number of atoms : 6 ( 4 equality)
+% Maximal formula depth : 7 ( 7 average)
+% Number of connectives : 4 ( 0 ~ ; 0 |; 1 &)
+% ( 3 <=>; 0 =>; 0 <=)
+% ( 0 <~>; 0 ~|; 0 ~&)
+% Number of predicates : 2 ( 0 propositional; 2-2 arity)
+% Number of functors : 0 ( 0 constant; --- arity)
+% Number of variables : 8 ( 0 singleton; 4 !; 4 ?)
+% Maximal term depth : 1 ( 1 average)
+% SPC : FOF_THM_RFO_SEQ
+
+% Comments :
+%--------------------------------------------------------------------------
+%----Problem axioms
+fof(pel52_1,axiom,
+ ( ? [Z,W] :
+ ! [X,Y] :
+ ( big_f(X,Y)
+ <=> ( X = Z
+ & Y = W ) ) )).
+
+fof(pel52,conjecture,
+ ( ? [W] :
+ ! [Y] :
+ ( ? [Z] :
+ ! [X] :
+ ( big_f(X,Y)
+ <=> X = Z )
+ <=> Y = W ) )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/SYN075-1.p b/test/regress/regress0/tptp/SYN075-1.p
new file mode 100644
index 000000000..40b49fa36
--- /dev/null
+++ b/test/regress/regress0/tptp/SYN075-1.p
@@ -0,0 +1,76 @@
+%--------------------------------------------------------------------------
+% File : SYN075-1 : TPTP v5.5.0. Released v1.0.0.
+% Domain : Syntactic
+% Problem : Pelletier Problem 52
+% Version : Especial.
+% English :
+
+% Refs : [Pel86] Pelletier (1986), Seventy-five Problems for Testing Au
+% Source : [Pel86]
+% Names : Pelletier 52 [Pel86]
+
+% Status : Unsatisfiable
+% Rating : 0.00 v5.5.0, 0.20 v5.3.0, 0.22 v5.2.0, 0.12 v5.1.0, 0.06 v5.0.0, 0.07 v4.1.0, 0.08 v4.0.1, 0.18 v4.0.0, 0.09 v3.7.0, 0.00 v3.3.0, 0.14 v3.2.0, 0.08 v3.1.0, 0.09 v2.7.0, 0.08 v2.6.0, 0.00 v2.5.0, 0.08 v2.4.0, 0.11 v2.2.1, 0.11 v2.2.0, 0.22 v2.1.0, 0.33 v2.0.0
+% Syntax : Number of clauses : 10 ( 4 non-Horn; 0 unit; 8 RR)
+% Number of atoms : 31 ( 17 equality)
+% Maximal clause size : 4 ( 3 average)
+% Number of predicates : 2 ( 0 propositional; 2-2 arity)
+% Number of functors : 5 ( 2 constant; 0-2 arity)
+% Number of variables : 23 ( 2 singleton)
+% Maximal term depth : 2 ( 1 average)
+% SPC : CNF_UNS_RFO_SEQ_NHN
+
+% Comments :
+%--------------------------------------------------------------------------
+cnf(clause_1,axiom,
+ ( ~ big_f(X,Y)
+ | X = a )).
+
+cnf(clause_2,axiom,
+ ( ~ big_f(X,Y)
+ | Y = b )).
+
+cnf(clause_3,axiom,
+ ( X != a
+ | Y != b
+ | big_f(X,Y) )).
+
+cnf(clause_4,negated_conjecture,
+ ( ~ big_f(Y,f(X))
+ | Y != g(X)
+ | f(X) = X )).
+
+cnf(clause_5,negated_conjecture,
+ ( ~ big_f(Y,f(X))
+ | Y = g(X)
+ | big_f(h(X,Z),f(X))
+ | ~ big_f(h(X,Z),f(X)) )).
+
+cnf(clause_6,negated_conjecture,
+ ( Y != g(X)
+ | big_f(Y,f(X))
+ | f(X) = X )).
+
+cnf(clause_7,negated_conjecture,
+ ( Y != g(X)
+ | big_f(Y,f(X))
+ | big_f(h(X,Z),f(X))
+ | h(X,Z) = Z )).
+
+cnf(clause_8,negated_conjecture,
+ ( Y != g(X)
+ | big_f(Y,f(X))
+ | h(X,Z) != Z
+ | ~ big_f(h(X,Z),f(X)) )).
+
+cnf(clause_9,negated_conjecture,
+ ( f(X) != X
+ | big_f(h(X,Z),f(X))
+ | h(X,Z) = Z )).
+
+cnf(clause_10,negated_conjecture,
+ ( f(X) != X
+ | h(X,Z) != Z
+ | ~ big_f(h(X,Z),f(X)) )).
+
+%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp/tff0-arith.p b/test/regress/regress0/tptp/tff0-arith.p
new file mode 100644
index 000000000..c0e9af25a
--- /dev/null
+++ b/test/regress/regress0/tptp/tff0-arith.p
@@ -0,0 +1,27 @@
+% example from the TFF0 paper
+% see https://sites.google.com/site/polymorphictptptff/relevant-links/tff-tfa
+%
+% Status : Theorem
+%
+tff(list_type,type, ( list: $tType )).
+tff(nil_type,type, ( nil: list )).
+tff(mycons_type,type,( mycons: ( $int * list ) > list )).
+tff(sorted_type,type,( fib_sorted: list > $o )).
+
+tff(empty_fib_sorted,axiom,(
+ fib_sorted(nil) )).
+tff(single_is_fib_sorted,axiom,(
+ ! [X: $int] : fib_sorted(mycons(X,nil)) )).
+tff(double_is_fib_sorted_if_ordered,axiom,(
+ ! [X: $int,Y: $int] :
+ ( $less(X,Y)
+ => fib_sorted(mycons(X,mycons(Y,nil))) ) )).
+tff(recursive_fib_sort,axiom,(
+ ! [X: $int,Y: $int,Z: $int,R: list] :
+ ( ( $less(X,Y)
+ & $greatereq(Z,$sum(X,Y))
+ & fib_sorted(mycons(Y,mycons(Z,R))) )
+ => fib_sorted(mycons(X,mycons(Y,mycons(Z,R)))) ) )).
+
+tff(check_list,conjecture,(
+ fib_sorted(mycons(1,mycons(2,mycons(4,nil)))) )).
diff --git a/test/regress/regress0/tptp/tff0.p b/test/regress/regress0/tptp/tff0.p
new file mode 100644
index 000000000..0402687bc
--- /dev/null
+++ b/test/regress/regress0/tptp/tff0.p
@@ -0,0 +1,37 @@
+% example from the TFF0 paper
+% see https://sites.google.com/site/polymorphictptptff/relevant-links/tff-tfa
+%
+% Status : Theorem
+%
+tff(student_type,type, ( student: $tType )).
+tff(professor_type,type,( professor: $tType )).
+tff(course_type,type, ( course: $tType )).
+tff(michael_type,type, ( michael: student )).
+tff(victor_type,type, ( victor: professor )).
+tff(csc410_type,type, ( csc410: course )).
+tff(enrolled_type,type, ( enrolled: ( student * course ) > $o )).
+tff(teaches_type,type, ( teaches: ( professor * course ) > $o )).
+tff(taught_by_type,type,( taughtby: ( student * professor ) > $o )).
+tff(coordinator_of_type,type,( coordinatorof: course > professor )).
+
+tff(student_enrolled_axiom,axiom,(
+ ! [X: student] : ? [Y: course] : enrolled(X,Y) )).
+tff(professor_teaches,axiom,(
+ ! [X: professor] : ? [Y: course] : teaches(X,Y) )).
+tff(course_enrolled,axiom,(
+ ! [X: course] : ? [Y: student] : enrolled(Y,X) )).
+tff(course_teaches,axiom,(
+ ! [X: course] : ? [Y: professor] : teaches(Y,X) )).
+tff(coordinator_teaches,axiom,(
+ ! [X: course] : teaches(coordinatorof(X),X) )).
+tff(student_enrolled_taught,axiom,(
+ ! [X: student,Y: course] :
+ ( enrolled(X,Y)
+ => ! [Z: professor] : ( teaches(Z,Y) => taughtby(X,Z) ) ) )).
+tff(michael_enrolled_csc410_axiom,axiom,(
+ enrolled(michael,csc410) )).
+tff(victor_coordinator_csc410_axiom,axiom,(
+ coordinatorof(csc410) = victor )).
+
+tff(teaching_conjecture,conjecture,(
+ taughtby(michael,victor) )).
diff --git a/test/regress/regress0/tptp_parser.p b/test/regress/regress0/tptp/tptp_parser.p
index 0be0adbbf..9c10d5bd3 100644
--- a/test/regress/regress0/tptp_parser.p
+++ b/test/regress/regress0/tptp/tptp_parser.p
@@ -1,5 +1,4 @@
-% EXPECT: unsat
-% EXIT: 20
+% Status: Unsatisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser10.p b/test/regress/regress0/tptp/tptp_parser10.p
index 90db619e7..d6a257121 100644
--- a/test/regress/regress0/tptp_parser10.p
+++ b/test/regress/regress0/tptp/tptp_parser10.p
@@ -1,5 +1,4 @@
-% EXPECT: unsat
-% EXIT: 20
+% Status: Theorem
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser2.p b/test/regress/regress0/tptp/tptp_parser2.p
index 83a5f7b83..e165b6b2f 100644
--- a/test/regress/regress0/tptp_parser2.p
+++ b/test/regress/regress0/tptp/tptp_parser2.p
@@ -1,5 +1,4 @@
-% EXPECT: unsat
-% EXIT: 20
+% Status: Unsatisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser3.p b/test/regress/regress0/tptp/tptp_parser3.p
index 3677e6ffe..2840892bc 100644
--- a/test/regress/regress0/tptp_parser3.p
+++ b/test/regress/regress0/tptp/tptp_parser3.p
@@ -1,5 +1,4 @@
-% EXPECT: unsat
-% EXIT: 20
+% Status: Unsatisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser4.p b/test/regress/regress0/tptp/tptp_parser4.p
index 6c5bd29da..448db77d2 100644
--- a/test/regress/regress0/tptp_parser4.p
+++ b/test/regress/regress0/tptp/tptp_parser4.p
@@ -1,5 +1,4 @@
-% EXPECT: unsat
-% EXIT: 20
+% Status: Unsatisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser5.p b/test/regress/regress0/tptp/tptp_parser5.p
index 23ddf3e60..c90d1cdad 100644
--- a/test/regress/regress0/tptp_parser5.p
+++ b/test/regress/regress0/tptp/tptp_parser5.p
@@ -1,5 +1,4 @@
-% EXPECT: unknown
-% EXIT: 0
+% Status: Satisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser6.p b/test/regress/regress0/tptp/tptp_parser6.p
index 799bc4c6d..6283eb29a 100644
--- a/test/regress/regress0/tptp_parser6.p
+++ b/test/regress/regress0/tptp/tptp_parser6.p
@@ -1,5 +1,4 @@
-% EXPECT: unknown
-% EXIT: 0
+% Status: Satisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser7.p b/test/regress/regress0/tptp/tptp_parser7.p
index f87c3484c..73c2b3834 100644
--- a/test/regress/regress0/tptp_parser7.p
+++ b/test/regress/regress0/tptp/tptp_parser7.p
@@ -1,5 +1,4 @@
-% EXPECT: unknown
-% EXIT: 0
+% Status: Satisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/tptp_parser8.p b/test/regress/regress0/tptp/tptp_parser8.p
index 4bb2694ea..da281151b 100644
--- a/test/regress/regress0/tptp_parser8.p
+++ b/test/regress/regress0/tptp/tptp_parser8.p
@@ -1,5 +1,4 @@
-% EXPECT: unknown
-% EXIT: 0
+% Status: Satisfiable
%--------------------------------------------------------------------------
include('tptp_parser7.p').
diff --git a/test/regress/regress0/tptp_parser9.p b/test/regress/regress0/tptp/tptp_parser9.p
index bcbb88598..9bed19702 100644
--- a/test/regress/regress0/tptp_parser9.p
+++ b/test/regress/regress0/tptp/tptp_parser9.p
@@ -1,5 +1,4 @@
-% EXPECT: unknown
-% EXIT: 0
+% Status: CounterSatisfiable
%--------------------------------------------------------------------------
diff --git a/test/regress/regress0/uf/Makefile.am b/test/regress/regress0/uf/Makefile.am
index 66ce8e3e6..bf9a36df1 100644
--- a/test/regress/regress0/uf/Makefile.am
+++ b/test/regress/regress0/uf/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/uflia/Makefile.am b/test/regress/regress0/uflia/Makefile.am
index f5ded6b88..2ef7be862 100644
--- a/test/regress/regress0/uflia/Makefile.am
+++ b/test/regress/regress0/uflia/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -17,12 +21,10 @@ MAKEFLAGS = -k
# Regression tests for SMT inputs
SMT_TESTS = \
- xs-09-16-3-4-1-5.smt \
xs-09-16-3-4-1-5.delta01.smt \
xs-09-16-3-4-1-5.delta02.smt \
xs-09-16-3-4-1-5.delta03.smt \
xs-09-16-3-4-1-5.delta04.smt \
- error0.smt2 \
error1.smt \
error0.delta01.smt \
simple_cyclic2.smt2 \
@@ -36,7 +38,6 @@ SMT2_TESTS = \
check04.smt2 \
DRAGON_11_e1_2450.ec.minimized.smt2 \
FIREFLY_3_e2_2236_e7_3681.ec.core.smt2 \
- FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2 \
FIREFLY_luke_1b_e2_3049_e7_1173.ec.minimized.smt2 \
stalmark_e7_27_e7_31.ec.minimized.smt2 \
stalmark_e7_27_e7_31.ec.smt2 \
@@ -63,7 +64,6 @@ EXTRA_DIST = $(TESTS) \
check04.smt2.expect \
DRAGON_11_e1_2450.ec.minimized.smt2.expect \
FIREFLY_3_e2_2236_e7_3681.ec.core.smt2.expect \
- FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect \
speed2_e8_449_e8_517.ec.smt2.expect \
stalmark_e7_27_e7_31.ec.minimized.smt2.expect \
stalmark_e7_27_e7_31.ec.smt2.expect \
diff --git a/test/regress/regress0/uflra/Makefile.am b/test/regress/regress0/uflra/Makefile.am
index 3491909e3..63d362bf9 100644
--- a/test/regress/regress0/uflra/Makefile.am
+++ b/test/regress/regress0/uflra/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -32,11 +36,8 @@ SMT_TESTS = \
pb_real_10_0200_10_22.smt \
pb_real_10_0200_10_26.smt \
pb_real_10_0200_10_29.smt \
- incorrect2.smt \
- incorrect1.smt \
incorrect1.delta01.smt \
incorrect1.delta02.smt \
- error1.smt \
neq-deltacomp.smt \
fuzz01.smt
diff --git a/test/regress/regress0/unconstrained/Makefile.am b/test/regress/regress0/unconstrained/Makefile.am
index 9a6ca29ba..c9a38d7b1 100644
--- a/test/regress/regress0/unconstrained/Makefile.am
+++ b/test/regress/regress0/unconstrained/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/arith/DTP_k2_n35_c175_s15.smt2 b/test/regress/regress1/DTP_k2_n35_c175_s15.smt2
index 20f4bf5a9..20f4bf5a9 100644
--- a/test/regress/regress0/arith/DTP_k2_n35_c175_s15.smt2
+++ b/test/regress/regress1/DTP_k2_n35_c175_s15.smt2
diff --git a/test/regress/regress0/uflia/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2 b/test/regress/regress1/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2
index 25f006d30..25f006d30 100644
--- a/test/regress/regress0/uflia/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2
+++ b/test/regress/regress1/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2
diff --git a/test/regress/regress0/uflia/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect b/test/regress/regress1/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect
index a06e9864e..a06e9864e 100644
--- a/test/regress/regress0/uflia/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect
+++ b/test/regress/regress1/FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect
diff --git a/test/regress/regress1/GEO123+1.minimized.smt2 b/test/regress/regress1/GEO123+1.minimized.smt2
new file mode 100644
index 000000000..8cc1fa7fd
--- /dev/null
+++ b/test/regress/regress1/GEO123+1.minimized.smt2
@@ -0,0 +1,397 @@
+; COMMAND-LINE: --incremental
+; EXPECT: sat
+; EXPECT: sat
+; EXIT: 10
+;
+; This is a benchmark demonstrating a nasty incremental bug in the UF
+; symmetry breaker, now fixed.
+;
+(set-logic QF_UF)
+(declare-fun _substvar_29615_ () Bool)
+(declare-sort T 0)
+(declare-fun incident_o (T T) Bool)
+(declare-fun sK25 () T)
+(declare-fun sK26 () T)
+(declare-fun ordered_by (T T T) Bool)
+(declare-fun sK21 (T T) T)
+(declare-fun incident_c (T T) Bool)
+(declare-fun between_o (T T T T) Bool)
+(declare-fun start_point (T T) Bool)
+(declare-fun sK12 (T T) T)
+(declare-fun meet (T T T) Bool)
+(declare-fun end_point (T T) Bool)
+(declare-fun inner_point (T T) Bool)
+(declare-fun part_of (T T) Bool)
+(declare-fun open (T) Bool)
+(declare-fun sK22 (T T) T)
+(declare-fun sK19 (T) T)
+(declare-fun sum (T T) T)
+(declare-fun sK4 (T T T) T)
+(declare-fun sK2 (T T) T)
+(declare-fun sK3 (T T) T)
+(declare-fun sK0 (T T) T)
+(declare-fun sK1 (T T T) T)
+(declare-fun sK24 () T)
+(declare-fun iProver_c13 () T)
+(declare-fun iProver_c41 () T)
+(declare-fun iProver_c14 () T)
+(assert (incident_o sK26 sK24))
+(assert (not (ordered_by sK24 sK25 sK26)))
+(assert (not (= sK25 sK26)))
+(assert (start_point (sK19 sK24) sK24))
+(check-sat)
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 sK24 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 sK24 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 sK24 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 sK24 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK24 sK25))) (or (= sK25 sK24) (not (incident_c _let_0 sK25)) (not (incident_c _let_0 sK24)))))
+(assert (let ((_let_0 (sK12 iProver_c13 sK25))) (or (= sK25 iProver_c13) (not (incident_c _let_0 sK25)) (not (incident_c _let_0 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 sK24 sK25))) (or (= _let_1 _let_0) (not (part_of _let_0 _let_1)) (open _let_0)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 iProver_c13 sK25))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 iProver_c13 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 sK25))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 iProver_c13 sK25))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 sK24 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK0 iProver_c13 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 sK24)) (not (meet sK24 sK25 sK24)) (end_point _let_0 sK25))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (not (incident_c _let_0 iProver_c13)) (not (meet iProver_c14 sK25 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 sK24)) (not (meet sK24 sK25 sK24)) (end_point _let_0 sK24))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 iProver_c13)) (not (meet iProver_c14 sK25 iProver_c13)) (end_point _let_0 iProver_c13))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 sK24)) (incident_c (sK4 sK24 sK25 _let_0) sK25) (meet _let_0 sK25 sK24))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 iProver_c13)) (incident_c (sK4 iProver_c13 sK25 _let_0) sK25) (meet _let_0 sK25 iProver_c13))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 sK24)) (meet _let_0 sK25 sK24) (incident_c (sK4 sK24 sK25 _let_0) sK24))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 iProver_c13)) (meet _let_0 sK25 iProver_c13) (incident_c (sK4 iProver_c13 sK25 _let_0) iProver_c13))))
+(assert (let ((_let_0 (sK4 sK24 sK25 (sK12 sK26 sK25)))) (or (not (incident_c (sK12 sK26 sK25) sK25)) (not (incident_c (sK12 sK26 sK25) sK24)) (meet (sK12 sK26 sK25) sK25 sK24) (not (end_point _let_0 sK25)) (not (end_point _let_0 sK24)))))
+(assert (let ((_let_0 (sK4 iProver_c13 sK25 (sK12 sK26 sK25)))) (or (not (incident_c (sK12 sK26 sK25) sK25)) (not (incident_c (sK12 sK26 sK25) iProver_c13)) (meet (sK12 sK26 sK25) sK25 iProver_c13) (not (end_point _let_0 sK25)) (not (end_point _let_0 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (inner_point _let_0 sK25))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (part_of sK25 sK24))) (or (not (part_of sK24 sK24)) (not (incident_c _let_0 sK25)) _let_1 (not _let_1) (part_of sK24 sK25) (not (incident_c _let_0 sK24)) (not (end_point _let_0 sK24))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (part_of iProver_c13 iProver_c14)) (not (incident_c _let_0 sK25)) (part_of sK25 iProver_c13) (part_of iProver_c13 sK25) (not (incident_c _let_0 iProver_c13)) (not (part_of sK25 iProver_c14)) (not (end_point _let_0 iProver_c14)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (part_of (sK2 sK25 _let_0) sK25))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (part_of (sK3 sK25 _let_0) sK25))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (incident_c _let_0 (sK2 sK25 _let_0)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (incident_c _let_0 (sK3 sK25 _let_0)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (not (part_of (sK2 sK25 _let_0) (sK3 sK25 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (end_point _let_0 sK25) (not (part_of (sK3 sK25 _let_0) (sK2 sK25 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (incident_c _let_0 (sum sK25 sK24)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (incident_c _let_0 (sum sK25 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (incident_c _let_0 (sum sK24 sK25)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (incident_c _let_0 (sum iProver_c13 sK25)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK0 sK24 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK0 iProver_c41 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK12 sK24 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK12 iProver_c13 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK12 iProver_c41 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK0 iProver_c13 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (part_of sK25 sK24)) (incident_c _let_0 sK24))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (not (incident_c _let_0 sK25)) (not (part_of sK25 iProver_c13)) (incident_c _let_0 iProver_c13))))
+(assert (or (part_of sK24 sK25) (not (incident_c (sK0 sK24 sK25) sK25))))
+(assert (or (part_of iProver_c13 sK25) (not (incident_c (sK0 iProver_c13 sK25) sK25))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 sK24 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 sK24 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 sK24 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 sK24 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK12 sK24 sK26))) (or (= sK26 sK24) (not (incident_c _let_0 sK26)) (not (incident_c _let_0 sK24)))))
+(assert (let ((_let_0 (sK12 iProver_c13 sK26))) (or (= sK26 iProver_c13) (not (incident_c _let_0 sK26)) (not (incident_c _let_0 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 sK24 sK26))) (or (= _let_1 _let_0) (not (part_of _let_0 _let_1)) (open _let_0)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 iProver_c13 sK26))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 iProver_c13 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 sK26))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 iProver_c13 sK26))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 sK24 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK0 iProver_c13 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 sK24)) (not (meet sK24 sK26 sK24)) (end_point _let_0 sK26))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (not (incident_c _let_0 iProver_c13)) (not (meet iProver_c14 sK26 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 sK24)) (not (meet sK24 sK26 sK24)) (end_point _let_0 sK24))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 iProver_c13)) (not (meet iProver_c14 sK26 iProver_c13)) (end_point _let_0 iProver_c13))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 sK24)) (incident_c (sK4 sK24 sK26 _let_0) sK26) (meet _let_0 sK26 sK24))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 iProver_c13)) (incident_c (sK4 iProver_c13 sK26 _let_0) sK26) (meet _let_0 sK26 iProver_c13))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 sK24)) (meet _let_0 sK26 sK24) (incident_c (sK4 sK24 sK26 _let_0) sK24))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 iProver_c13)) (meet _let_0 sK26 iProver_c13) (incident_c (sK4 iProver_c13 sK26 _let_0) iProver_c13))))
+(assert (let ((_let_0 (sK4 sK24 sK26 (sK12 sK25 sK26)))) (or (not (incident_c (sK12 sK25 sK26) sK26)) (not (incident_c (sK12 sK25 sK26) sK24)) (meet (sK12 sK25 sK26) sK26 sK24) (not (end_point _let_0 sK26)) (not (end_point _let_0 sK24)))))
+(assert (let ((_let_0 (sK4 iProver_c13 sK26 (sK12 sK25 sK26)))) (or (not (incident_c (sK12 sK25 sK26) sK26)) (not (incident_c (sK12 sK25 sK26) iProver_c13)) (meet (sK12 sK25 sK26) sK26 iProver_c13) (not (end_point _let_0 sK26)) (not (end_point _let_0 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (inner_point _let_0 sK26))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (part_of sK26 sK24))) (or (not (part_of sK24 sK24)) (not (incident_c _let_0 sK26)) (part_of sK24 sK26) _let_1 (not _let_1) (not (incident_c _let_0 sK24)) (not (end_point _let_0 sK24))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (part_of iProver_c13 iProver_c14)) (not (incident_c _let_0 sK26)) (part_of iProver_c13 sK26) (part_of sK26 iProver_c13) (not (incident_c _let_0 iProver_c13)) (not (part_of sK26 iProver_c14)) (not (end_point _let_0 iProver_c14)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (part_of (sK2 sK26 _let_0) sK26))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (part_of (sK3 sK26 _let_0) sK26))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (incident_c _let_0 (sK2 sK26 _let_0)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (incident_c _let_0 (sK3 sK26 _let_0)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (not (part_of (sK2 sK26 _let_0) (sK3 sK26 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (end_point _let_0 sK26) (not (part_of (sK3 sK26 _let_0) (sK2 sK26 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (incident_c _let_0 (sum sK26 sK24)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (incident_c _let_0 (sum sK26 iProver_c13)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (incident_c _let_0 (sum sK24 sK26)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (incident_c _let_0 (sum iProver_c13 sK26)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK0 sK24 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK0 iProver_c41 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK12 sK24 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK12 iProver_c13 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK12 iProver_c41 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK0 iProver_c13 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (part_of sK26 sK24)) (incident_c _let_0 sK24))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (not (incident_c _let_0 sK26)) (not (part_of sK26 iProver_c13)) (incident_c _let_0 iProver_c13))))
+(assert (or (part_of sK24 sK26) (not (incident_c (sK0 sK24 sK26) sK26))))
+(assert (or (part_of iProver_c13 sK26) (not (incident_c (sK0 iProver_c13 sK26) sK26))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK21 sK24 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (or (not (ordered_by sK25 _let_0 _let_1)) (not (ordered_by sK24 _let_0 _let_1)) (= sK25 sK24)))))
+(assert (let ((_let_0 (sK21 iProver_c13 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (or (not (ordered_by sK25 _let_0 _let_1)) (not (ordered_by iProver_c13 _let_0 _let_1)) (= sK25 iProver_c13)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (or (not (ordered_by sK25 _let_0 (sK22 sK26 sK25))) (incident_o _let_0 sK25))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (or (not (ordered_by sK25 (sK21 sK26 sK25) _let_0)) (incident_o _let_0 sK25))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK22 sK26 sK25))) (or (not (ordered_by sK25 _let_0 _let_1)) (not (ordered_by sK25 _let_1 sK24)) (between_o sK25 _let_0 _let_1 sK24)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK22 sK26 sK25))) (or (not (ordered_by sK25 _let_0 _let_1)) (not (ordered_by sK25 _let_1 iProver_c13)) (between_o sK25 _let_0 _let_1 iProver_c13)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK22 sK26 sK25))) (or (not (ordered_by sK25 _let_0 _let_1)) (not (ordered_by sK25 _let_1 sK24)) (between_o sK25 sK24 _let_1 _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK22 sK26 sK25))) (or (not (ordered_by sK25 _let_0 _let_1)) (not (ordered_by sK25 _let_1 iProver_c13)) (between_o sK25 iProver_c13 _let_1 _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 iProver_c13 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (or (= _let_1 _let_0) (not (part_of _let_0 _let_1)) (open _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK21 iProver_c13 sK25))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (or (= _let_1 _let_0) (not (part_of _let_0 _let_1)) (open _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK24 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK22 iProver_c41 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK24 sK25))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK21 iProver_c13 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c13 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum iProver_c13 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c13 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum iProver_c13 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 iProver_c13 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 iProver_c41 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK1 sK24 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 sK24) (= (sum _let_0 sK24) _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c14 sK25))) (let ((_let_2 (sK1 iProver_c13 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 iProver_c13) (= (sum _let_0 iProver_c13) _let_1))))))
+(assert (let ((_let_0 (sK22 iProver_c14 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK1 _let_0 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 _let_0) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK1 _let_0 iProver_c13 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum iProver_c13 _let_0) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (or (incident_c (sK1 _let_0 _let_0 _let_0) _let_0) (= (sum _let_0 _let_0) _let_0))))
+(assert (let ((_let_0 (sK22 iProver_c13 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (let ((_let_2 (sK1 iProver_c13 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 iProver_c13) (= (sum _let_0 iProver_c13) _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK1 _let_0 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (= (sum _let_0 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c13 sK25))) (let ((_let_2 (sK1 _let_0 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (= (sum _let_0 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 sK24 sK25))) (let ((_let_2 (sK1 _let_0 sK24 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 sK24) (incident_c _let_2 _let_0) (= (sum sK24 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK22 iProver_c14 sK25))) (let ((_let_2 (sK1 _let_0 iProver_c13 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 iProver_c13) (incident_c _let_2 _let_0) (= (sum iProver_c13 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK22 sK26 sK25))) (let ((_let_2 (sK1 sK24 _let_1 _let_0))) (or (incident_c _let_2 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 sK24) (= (sum _let_1 sK24) _let_0))))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (let ((_let_1 (sK22 sK26 sK25))) (let ((_let_2 (sK1 iProver_c13 _let_1 _let_0))) (or (incident_c _let_2 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 iProver_c13) (= (sum _let_1 iProver_c13) _let_0))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK1 sK24 _let_0 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum _let_0 sK24) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK1 iProver_c13 _let_0 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum _let_0 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK21 sK24 sK25))) (let ((_let_2 (sK1 sK24 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 sK24) (= (sum _let_0 sK24) _let_1))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK21 iProver_c14 sK25))) (let ((_let_2 (sK1 iProver_c13 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 iProver_c13) (= (sum _let_0 iProver_c13) _let_1))))))
+(assert (let ((_let_0 (sK21 iProver_c14 sK25))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_1 _let_0))) (let ((_let_3 (sK22 _let_1 _let_0))) (or (ordered_by _let_0 _let_2 _let_3) (ordered_by _let_1 _let_2 _let_3) (= _let_0 _let_1)))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (let ((_let_2 (sK21 _let_0 _let_1))) (let ((_let_3 (sK22 _let_0 _let_1))) (or (ordered_by _let_1 _let_2 _let_3) (ordered_by _let_0 _let_2 _let_3) (= _let_1 _let_0)))))))
+(assert (let ((_let_0 (sK21 sK24 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (or (not (ordered_by sK26 _let_0 _let_1)) (not (ordered_by sK24 _let_0 _let_1)) (= sK26 sK24)))))
+(assert (let ((_let_0 (sK21 iProver_c13 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (or (not (ordered_by sK26 _let_0 _let_1)) (not (ordered_by iProver_c13 _let_0 _let_1)) (= sK26 iProver_c13)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (or (not (ordered_by sK26 _let_0 (sK22 sK25 sK26))) (incident_o _let_0 sK26))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (or (not (ordered_by sK26 (sK21 sK25 sK26) _let_0)) (incident_o _let_0 sK26))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK22 sK25 sK26))) (or (not (ordered_by sK26 _let_0 _let_1)) (not (ordered_by sK26 _let_1 sK24)) (between_o sK26 _let_0 _let_1 sK24)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK22 sK25 sK26))) (or (not (ordered_by sK26 _let_0 _let_1)) (not (ordered_by sK26 _let_1 iProver_c13)) (between_o sK26 _let_0 _let_1 iProver_c13)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK22 sK25 sK26))) (or (not (ordered_by sK26 _let_0 _let_1)) (not (ordered_by sK26 _let_1 sK24)) (between_o sK26 sK24 _let_1 _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK22 sK25 sK26))) (or (not (ordered_by sK26 _let_0 _let_1)) (not (ordered_by sK26 _let_1 iProver_c13)) (between_o sK26 iProver_c13 _let_1 _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_1 _let_0))) (or (= _let_0 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (let ((_let_2 (sK12 _let_0 _let_1))) (or (= _let_1 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 _let_0))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 iProver_c13 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (or (= _let_1 _let_0) (not (part_of _let_0 _let_1)) (open _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK21 iProver_c13 sK26))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (or (= _let_0 _let_1) (not (part_of _let_1 _let_0)) (open _let_1)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (or (= _let_1 _let_0) (not (part_of _let_0 _let_1)) (open _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (or (= _let_1 _let_0) (open _let_0) (not (part_of _let_0 _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK24 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK22 iProver_c41 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK24 sK26))) (let ((_let_1 (sK1 sK24 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 sK24) _let_0)))))
+(assert (let ((_let_0 (sK21 iProver_c13 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c13 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum iProver_c13 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c13 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum iProver_c13 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 iProver_c13 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK21 iProver_c41 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK1 sK24 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 sK24) (= (sum _let_0 sK24) _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c14 sK26))) (let ((_let_2 (sK1 iProver_c13 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 iProver_c13) (= (sum _let_0 iProver_c13) _let_1))))))
+(assert (let ((_let_0 (sK22 iProver_c14 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK1 _let_0 sK24 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum sK24 _let_0) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK1 _let_0 iProver_c13 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum iProver_c13 _let_0) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (or (incident_c (sK1 _let_0 _let_0 _let_0) _let_0) (= (sum _let_0 _let_0) _let_0))))
+(assert (let ((_let_0 (sK22 iProver_c13 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (let ((_let_2 (sK1 iProver_c13 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 iProver_c13) (= (sum _let_0 iProver_c13) _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK1 _let_0 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (= (sum _let_0 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c13 sK26))) (let ((_let_2 (sK1 _let_0 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (= (sum _let_0 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 sK24 sK26))) (let ((_let_2 (sK1 _let_0 sK24 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 sK24) (incident_c _let_2 _let_0) (= (sum sK24 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK22 iProver_c14 sK26))) (let ((_let_2 (sK1 _let_0 iProver_c13 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 iProver_c13) (incident_c _let_2 _let_0) (= (sum iProver_c13 _let_0) _let_1))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK22 sK25 sK26))) (let ((_let_2 (sK1 sK24 _let_1 _let_0))) (or (incident_c _let_2 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 sK24) (= (sum _let_1 sK24) _let_0))))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (let ((_let_1 (sK22 sK25 sK26))) (let ((_let_2 (sK1 iProver_c13 _let_1 _let_0))) (or (incident_c _let_2 _let_0) (incident_c _let_2 _let_1) (incident_c _let_2 iProver_c13) (= (sum _let_1 iProver_c13) _let_0))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK1 sK24 _let_0 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 sK24) (= (sum _let_0 sK24) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK1 iProver_c13 _let_0 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c13) (= (sum _let_0 iProver_c13) _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK21 sK24 sK26))) (let ((_let_2 (sK1 sK24 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 sK24) (= (sum _let_0 sK24) _let_1))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK21 iProver_c14 sK26))) (let ((_let_2 (sK1 iProver_c13 _let_0 _let_1))) (or (incident_c _let_2 _let_1) (incident_c _let_2 _let_0) (incident_c _let_2 iProver_c13) (= (sum _let_0 iProver_c13) _let_1))))))
+(assert (let ((_let_0 (sK21 iProver_c14 sK26))) (let ((_let_1 (sK1 iProver_c13 iProver_c14 _let_0))) (or (incident_c _let_1 _let_0) (incident_c _let_1 iProver_c14) (incident_c _let_1 iProver_c13) (= (sum iProver_c14 iProver_c13) _let_0)))))
+(assert (or (= iProver_c13 iProver_c14) false false _substvar_29615_ false false))
+(assert (or (not (incident_c sK24 sK24)) (not (meet sK24 sK25 sK24)) (not (incident_c sK24 sK25)) (end_point sK24 sK25)))
+(assert (or (not (meet iProver_c14 sK25 iProver_c13)) (not (incident_c sK24 sK25)) (end_point sK24 sK25) (not (incident_c sK24 iProver_c13))))
+(assert (or (not (incident_c sK24 sK24)) (end_point sK24 sK24) (not (meet sK24 sK25 sK24)) (not (incident_c sK24 sK25))))
+(assert (or (not (meet iProver_c14 sK25 iProver_c13)) (not (incident_c sK24 sK25)) (not (incident_c sK24 iProver_c13)) (end_point sK24 iProver_c13)))
+(assert (or (not (incident_c sK24 sK24)) (meet sK24 sK25 sK24) (not (incident_c sK24 sK25)) (incident_c (sK4 sK24 sK25 sK24) sK25)))
+(assert (or (not (incident_c sK24 sK25)) (not (incident_c sK24 iProver_c13)) (incident_c (sK4 iProver_c13 sK25 sK24) sK25) (meet sK24 sK25 iProver_c13)))
+(assert (or (not (incident_c sK24 sK24)) (meet sK24 sK25 sK24) (not (incident_c sK24 sK25)) (incident_c (sK4 sK24 sK25 sK24) sK24)))
+(assert (or (not (incident_c sK24 sK25)) (not (incident_c sK24 iProver_c13)) (meet sK24 sK25 iProver_c13) (incident_c (sK4 iProver_c13 sK25 sK24) iProver_c13)))
+(assert (let ((_let_0 (sK4 sK24 sK25 sK24))) (or (not (incident_c sK24 sK24)) (meet sK24 sK25 sK24) (not (incident_c sK24 sK25)) (not (end_point _let_0 sK25)) (not (end_point _let_0 sK24)))))
+(assert (let ((_let_0 (sK4 iProver_c13 sK25 sK24))) (or (not (incident_c sK24 sK25)) (not (incident_c sK24 iProver_c13)) (meet sK24 sK25 iProver_c13) (not (end_point _let_0 sK25)) (not (end_point _let_0 iProver_c13)))))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (inner_point sK24 sK25)))
+(assert (let ((_let_0 (part_of sK25 sK24))) (or (not (incident_c sK24 sK24)) (not (part_of sK24 sK24)) (not (end_point sK24 sK24)) _let_0 (not _let_0) (part_of sK24 sK25) (not (incident_c sK24 sK25)))))
+(assert (or (not (part_of iProver_c13 iProver_c14)) (part_of sK25 iProver_c13) (part_of iProver_c13 sK25) (not (part_of sK25 iProver_c14)) (not (incident_c sK24 sK25)) (not (incident_c sK24 iProver_c13)) (not (end_point sK24 iProver_c14))))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (part_of (sK2 sK25 sK24) sK25)))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (part_of (sK3 sK25 sK24) sK25)))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (incident_c sK24 (sK2 sK25 sK24))))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (incident_c sK24 (sK3 sK25 sK24))))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (not (part_of (sK2 sK25 sK24) (sK3 sK25 sK24)))))
+(assert (or (not (incident_c sK24 sK25)) (end_point sK24 sK25) (not (part_of (sK3 sK25 sK24) (sK2 sK25 sK24)))))
+(assert (or (not (incident_c sK24 sK25)) (incident_c sK24 (sum sK25 sK24))))
+(assert (or (not (incident_c sK24 sK25)) (incident_c sK24 (sum sK25 iProver_c13))))
+(assert (or (not (incident_c sK24 sK25)) (incident_c sK24 (sum sK24 sK25))))
+(assert (or (not (incident_c sK24 sK25)) (incident_c sK24 (sum iProver_c13 sK25))))
+(assert (or (incident_c sK24 sK24) (not (part_of sK25 sK24)) (not (incident_c sK24 sK25))))
+(assert (or (not (part_of sK25 iProver_c13)) (not (incident_c sK24 sK25)) (incident_c sK24 iProver_c13)))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK21 _let_0 sK24))) (let ((_let_2 (sK22 _let_0 sK24))) (or (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2) (= sK24 _let_0))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 _let_0 sK24))) (or (= sK24 _let_0) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (open _let_0) (= sK24 _let_0) (not (part_of _let_0 sK24)))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (or (open sK24) (not (part_of sK24 _let_0)) (= _let_0 sK24))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK21 sK24 _let_0))) (let ((_let_2 (sK22 sK24 _let_0))) (or (= _let_0 sK24) (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2))))))
+(assert (let ((_let_0 (sK12 sK26 sK25))) (let ((_let_1 (sK12 sK24 _let_0))) (or (= _let_0 sK24) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (or (not (incident_c sK24 sK24)) (not (meet sK24 sK26 sK24)) (not (incident_c sK24 sK26)) (end_point sK24 sK26)))
+(assert (or (not (meet iProver_c14 sK26 iProver_c13)) (not (incident_c sK24 iProver_c13)) (not (incident_c sK24 sK26)) (end_point sK24 sK26)))
+(assert (or (not (incident_c sK24 sK24)) (end_point sK24 sK24) (not (meet sK24 sK26 sK24)) (not (incident_c sK24 sK26))))
+(assert (or (not (meet iProver_c14 sK26 iProver_c13)) (not (incident_c sK24 iProver_c13)) (end_point sK24 iProver_c13) (not (incident_c sK24 sK26))))
+(assert (or (not (incident_c sK24 sK24)) (meet sK24 sK26 sK24) (not (incident_c sK24 sK26)) (incident_c (sK4 sK24 sK26 sK24) sK26)))
+(assert (or (not (incident_c sK24 iProver_c13)) (not (incident_c sK24 sK26)) (incident_c (sK4 iProver_c13 sK26 sK24) sK26) (meet sK24 sK26 iProver_c13)))
+(assert (or (not (incident_c sK24 sK24)) (meet sK24 sK26 sK24) (not (incident_c sK24 sK26)) (incident_c (sK4 sK24 sK26 sK24) sK24)))
+(assert (or (not (incident_c sK24 iProver_c13)) (not (incident_c sK24 sK26)) (meet sK24 sK26 iProver_c13) (incident_c (sK4 iProver_c13 sK26 sK24) iProver_c13)))
+(assert (let ((_let_0 (sK4 sK24 sK26 sK24))) (or (not (incident_c sK24 sK24)) (meet sK24 sK26 sK24) (not (incident_c sK24 sK26)) (not (end_point _let_0 sK26)) (not (end_point _let_0 sK24)))))
+(assert (let ((_let_0 (sK4 iProver_c13 sK26 sK24))) (or (not (incident_c sK24 iProver_c13)) (not (incident_c sK24 sK26)) (meet sK24 sK26 iProver_c13) (not (end_point _let_0 sK26)) (not (end_point _let_0 iProver_c13)))))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (inner_point sK24 sK26)))
+(assert (let ((_let_0 (part_of sK26 sK24))) (or (not (incident_c sK24 sK24)) (not (part_of sK24 sK24)) (not (end_point sK24 sK24)) (part_of sK24 sK26) _let_0 (not _let_0) (not (incident_c sK24 sK26)))))
+(assert (or (not (part_of iProver_c13 iProver_c14)) (part_of iProver_c13 sK26) (part_of sK26 iProver_c13) (not (part_of sK26 iProver_c14)) (not (incident_c sK24 iProver_c13)) (not (end_point sK24 iProver_c14)) (not (incident_c sK24 sK26))))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (part_of (sK2 sK26 sK24) sK26)))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (part_of (sK3 sK26 sK24) sK26)))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (incident_c sK24 (sK2 sK26 sK24))))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (incident_c sK24 (sK3 sK26 sK24))))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (not (part_of (sK2 sK26 sK24) (sK3 sK26 sK24)))))
+(assert (or (not (incident_c sK24 sK26)) (end_point sK24 sK26) (not (part_of (sK3 sK26 sK24) (sK2 sK26 sK24)))))
+(assert (or (not (incident_c sK24 sK26)) (incident_c sK24 (sum sK26 sK24))))
+(assert (or (not (incident_c sK24 sK26)) (incident_c sK24 (sum sK26 iProver_c13))))
+(assert (or (not (incident_c sK24 sK26)) (incident_c sK24 (sum sK24 sK26))))
+(assert (or (not (incident_c sK24 sK26)) (incident_c sK24 (sum iProver_c13 sK26))))
+(assert (or (incident_c sK24 sK24) (not (part_of sK26 sK24)) (not (incident_c sK24 sK26))))
+(assert (or (not (part_of sK26 iProver_c13)) (incident_c sK24 iProver_c13) (not (incident_c sK24 sK26))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK21 _let_0 sK24))) (let ((_let_2 (sK22 _let_0 sK24))) (or (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2) (= sK24 _let_0))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 _let_0 sK24))) (or (= sK24 _let_0) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (open _let_0) (= sK24 _let_0) (not (part_of _let_0 sK24)))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (or (open sK24) (not (part_of sK24 _let_0)) (= _let_0 sK24))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK21 sK24 _let_0))) (let ((_let_2 (sK22 sK24 _let_0))) (or (= _let_0 sK24) (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2))))))
+(assert (let ((_let_0 (sK12 sK25 sK26))) (let ((_let_1 (sK12 sK24 _let_0))) (or (= _let_0 sK24) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (let ((_let_0 (sK1 sK24 sK24 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 sK24)) (= (sum sK24 sK24) sK25))))
+(assert (let ((_let_0 (sK1 iProver_c13 iProver_c14 sK25))) (or (not (incident_c _let_0 sK25)) (not (incident_c _let_0 iProver_c14)) (= (sum iProver_c14 iProver_c13) sK25))))
+(assert (let ((_let_0 (sK1 sK24 sK24 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 sK24)) (= (sum sK24 sK24) sK26))))
+(assert (let ((_let_0 (sK1 iProver_c13 iProver_c14 sK26))) (or (not (incident_c _let_0 sK26)) (not (incident_c _let_0 iProver_c14)) (= (sum iProver_c14 iProver_c13) sK26))))
+(assert (let ((_let_0 (sum sK24 sK24))) (or (open sK25) (= _let_0 sK25) (not (part_of sK25 _let_0)))))
+(assert (let ((_let_0 (sum iProver_c13 iProver_c14))) (or (open sK25) (= _let_0 sK25) (not (part_of sK25 _let_0)))))
+(assert (let ((_let_0 (sum sK24 sK24))) (or (open sK26) (= _let_0 sK26) (not (part_of sK26 _let_0)))))
+(assert (let ((_let_0 (sum iProver_c13 iProver_c14))) (or (open sK26) (= _let_0 sK26) (not (part_of sK26 _let_0)))))
+(assert (let ((_let_0 (sum sK24 sK24))) (or (open _let_0) (not (part_of _let_0 sK25)) (= sK25 _let_0))))
+(assert (let ((_let_0 (sum iProver_c13 iProver_c14))) (or (open _let_0) (not (part_of _let_0 sK25)) (= sK25 _let_0))))
+(assert (let ((_let_0 (sum sK24 sK24))) (or (open _let_0) (not (part_of _let_0 sK26)) (= sK26 _let_0))))
+(assert (let ((_let_0 (sum iProver_c13 iProver_c14))) (or (open _let_0) (not (part_of _let_0 sK26)) (= sK26 _let_0))))
+(assert (let ((_let_0 (sum sK24 sK24))) (let ((_let_1 (sK12 _let_0 sK25))) (or (= sK25 _let_0) (incident_c _let_1 _let_0) (incident_c _let_1 sK25)))))
+(assert (let ((_let_0 (sum iProver_c13 iProver_c14))) (let ((_let_1 (sK12 _let_0 sK25))) (or (= sK25 _let_0) (incident_c _let_1 _let_0) (incident_c _let_1 sK25)))))
+(assert (let ((_let_0 (sum sK24 sK24))) (let ((_let_1 (sK12 _let_0 sK26))) (or (= sK26 _let_0) (incident_c _let_1 _let_0) (incident_c _let_1 sK26)))))
+(assert (let ((_let_0 (sum iProver_c13 iProver_c14))) (let ((_let_1 (sK12 _let_0 sK26))) (or (= sK26 _let_0) (incident_c _let_1 _let_0) (incident_c _let_1 sK26)))))
+(assert (let ((_let_0 (sK19 sK24))) (or (not (incident_o sK25 sK24)) (not (start_point _let_0 sK24)) (ordered_by sK24 _let_0 sK25) (= _let_0 sK25))))
+(assert (let ((_let_0 (sK19 iProver_c13))) (or (not (start_point _let_0 iProver_c13)) (not (incident_o sK25 iProver_c13)) (ordered_by iProver_c13 _let_0 sK25) (= _let_0 sK25))))
+(assert (let ((_let_0 (sK19 sK24))) (or (not (incident_o sK26 sK24)) (not (start_point _let_0 sK24)) (ordered_by sK24 _let_0 sK26) (= _let_0 sK26))))
+(assert (let ((_let_0 (sK19 iProver_c13))) (or (not (start_point _let_0 iProver_c13)) (not (incident_o sK26 iProver_c13)) (ordered_by iProver_c13 _let_0 sK26) (= _let_0 sK26))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (or (incident_o _let_0 sK26) (not (ordered_by sK26 _let_0 sK24)))))
+(assert (or (not (ordered_by sK26 (sK21 sK25 sK26) sK24)) (incident_o sK24 sK26)))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (or (not (ordered_by sK26 _let_0 sK24)) (not (ordered_by sK26 sK24 sK24)) (between_o sK26 _let_0 sK24 sK24))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (or (not (ordered_by sK26 _let_0 sK24)) (not (ordered_by sK26 sK24 iProver_c13)) (between_o sK26 _let_0 sK24 iProver_c13))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (or (not (ordered_by sK26 _let_0 sK24)) (not (ordered_by sK26 sK24 sK24)) (between_o sK26 sK24 sK24 _let_0))))
+(assert (let ((_let_0 (sK21 sK25 sK26))) (or (not (ordered_by sK26 _let_0 sK24)) (not (ordered_by sK26 sK24 iProver_c13)) (between_o sK26 iProver_c13 sK24 _let_0))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK21 _let_0 sK24))) (let ((_let_2 (sK22 _let_0 sK24))) (or (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2) (= sK24 _let_0))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK12 _let_0 sK24))) (or (= sK24 _let_0) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (or (open _let_0) (= sK24 _let_0) (not (part_of _let_0 sK24)))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (or (open sK24) (not (part_of sK24 _let_0)) (= _let_0 sK24))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK21 sK24 _let_0))) (let ((_let_2 (sK22 sK24 _let_0))) (or (= _let_0 sK24) (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2))))))
+(assert (let ((_let_0 (sK22 sK25 sK26))) (let ((_let_1 (sK12 sK24 _let_0))) (or (= _let_0 sK24) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (or (incident_o _let_0 sK25) (not (ordered_by sK25 _let_0 sK24)))))
+(assert (or (not (ordered_by sK25 (sK21 sK26 sK25) sK24)) (incident_o sK24 sK25)))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (or (not (ordered_by sK25 _let_0 sK24)) (not (ordered_by sK25 sK24 sK24)) (between_o sK25 _let_0 sK24 sK24))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (or (not (ordered_by sK25 _let_0 sK24)) (not (ordered_by sK25 sK24 iProver_c13)) (between_o sK25 _let_0 sK24 iProver_c13))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (or (not (ordered_by sK25 _let_0 sK24)) (not (ordered_by sK25 sK24 sK24)) (between_o sK25 sK24 sK24 _let_0))))
+(assert (let ((_let_0 (sK21 sK26 sK25))) (or (not (ordered_by sK25 _let_0 sK24)) (not (ordered_by sK25 sK24 iProver_c13)) (between_o sK25 iProver_c13 sK24 _let_0))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK21 _let_0 sK24))) (let ((_let_2 (sK22 _let_0 sK24))) (or (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2) (= sK24 _let_0))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK12 _let_0 sK24))) (or (= sK24 _let_0) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (or (open _let_0) (= sK24 _let_0) (not (part_of _let_0 sK24)))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (or (open sK24) (not (part_of sK24 _let_0)) (= _let_0 sK24))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK21 sK24 _let_0))) (let ((_let_2 (sK22 sK24 _let_0))) (or (= _let_0 sK24) (ordered_by sK24 _let_1 _let_2) (ordered_by _let_0 _let_1 _let_2))))))
+(assert (let ((_let_0 (sK22 sK26 sK25))) (let ((_let_1 (sK12 sK24 _let_0))) (or (= _let_0 sK24) (incident_c _let_1 sK24) (incident_c _let_1 _let_0)))))
+(check-sat)
+
diff --git a/test/regress/regress1/Makefile.am b/test/regress/regress1/Makefile.am
index bcbb0a618..674f5c75e 100644
--- a/test/regress/regress1/Makefile.am
+++ b/test/regress/regress1/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = . arith
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -18,6 +22,10 @@ MAKEFLAGS = -k
# put it below in "TESTS +="
TESTS = bug136.smt \
bug148.smt \
+ bug394.smt2 \
+ DTP_k2_n35_c175_s15.smt2 \
+ GEO123+1.minimized.smt2 \
+ error1.smt \
friedman_n4_i5.smt \
hole7.cvc \
hole8.cvc \
@@ -28,9 +36,19 @@ TESTS = bug136.smt \
ooo.tag10.smt2 \
hash_sat_06_19.smt2 \
hash_sat_09_09.smt2 \
- ooo.rf6.smt2
+ ooo.rf6.smt2 \
+ auflia-fuzz06.smt \
+ piVC_5581bd.smt2 \
+ typed_v1l50016-simp.cvc \
+ FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2 \
+ xs-09-16-3-4-1-5.smt \
+ xs-09-16-3-4-1-5.decn.smt \
+ uflia-error0.smt2
-EXTRA_DIST = $(TESTS)
+EXTRA_DIST = $(TESTS) \
+ FIREFLY_3_e2_2236_e7_3681.ec.minimized.smt2.expect \
+ uflia-error0.smt2.expect \
+ xs-09-16-3-4-1-5.decn.smt.expect
#if CVC4_BUILD_PROFILE_COMPETITION
#else
diff --git a/test/regress/regress1/arith/Makefile.am b/test/regress/regress1/arith/Makefile.am
index bfbafdd3a..9d8534b30 100644
--- a/test/regress/regress1/arith/Makefile.am
+++ b/test/regress/regress1/arith/Makefile.am
@@ -1,4 +1,8 @@
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/regress0/auflia/fuzz06.smt b/test/regress/regress1/auflia-fuzz06.smt
index 88c2a9d5c..88c2a9d5c 100644
--- a/test/regress/regress0/auflia/fuzz06.smt
+++ b/test/regress/regress1/auflia-fuzz06.smt
diff --git a/test/regress/regress0/push-pop/bug394.smt2 b/test/regress/regress1/bug394.smt2
index cb2bc32a8..cb2bc32a8 100644
--- a/test/regress/regress0/push-pop/bug394.smt2
+++ b/test/regress/regress1/bug394.smt2
diff --git a/test/regress/regress0/uflia/error0.smt2 b/test/regress/regress1/error0.smt2
index 73177a252..73177a252 100644
--- a/test/regress/regress0/uflia/error0.smt2
+++ b/test/regress/regress1/error0.smt2
diff --git a/test/regress/regress0/uflra/error1.smt b/test/regress/regress1/error1.smt
index 9b2cabedf..9b2cabedf 100644
--- a/test/regress/regress0/uflra/error1.smt
+++ b/test/regress/regress1/error1.smt
diff --git a/test/regress/regress0/quantifiers/piVC_5581bd.smt2 b/test/regress/regress1/piVC_5581bd.smt2
index 78baeea84..78baeea84 100644
--- a/test/regress/regress0/quantifiers/piVC_5581bd.smt2
+++ b/test/regress/regress1/piVC_5581bd.smt2
diff --git a/test/regress/regress0/datatypes/typed_v1l50016-simp.cvc b/test/regress/regress1/typed_v1l50016-simp.cvc
index b273d99e9..b273d99e9 100644
--- a/test/regress/regress0/datatypes/typed_v1l50016-simp.cvc
+++ b/test/regress/regress1/typed_v1l50016-simp.cvc
diff --git a/test/regress/regress0/decision/uflia-error0.smt2 b/test/regress/regress1/uflia-error0.smt2
index 73177a252..73177a252 100644
--- a/test/regress/regress0/decision/uflia-error0.smt2
+++ b/test/regress/regress1/uflia-error0.smt2
diff --git a/test/regress/regress0/decision/uflia-error0.smt2.expect b/test/regress/regress1/uflia-error0.smt2.expect
index b862d0b39..b862d0b39 100644
--- a/test/regress/regress0/decision/uflia-error0.smt2.expect
+++ b/test/regress/regress1/uflia-error0.smt2.expect
diff --git a/test/regress/regress0/uflia/xs-09-16-3-4-1-5.smt b/test/regress/regress1/xs-09-16-3-4-1-5.decn.smt
index 549306c5b..549306c5b 100644
--- a/test/regress/regress0/uflia/xs-09-16-3-4-1-5.smt
+++ b/test/regress/regress1/xs-09-16-3-4-1-5.decn.smt
diff --git a/test/regress/regress1/xs-09-16-3-4-1-5.decn.smt.expect b/test/regress/regress1/xs-09-16-3-4-1-5.decn.smt.expect
new file mode 100644
index 000000000..b862d0b39
--- /dev/null
+++ b/test/regress/regress1/xs-09-16-3-4-1-5.decn.smt.expect
@@ -0,0 +1,3 @@
+% COMMAND-LINE: --decision=justification
+% EXPECT: unsat
+% EXIT: 20
diff --git a/test/regress/regress1/xs-09-16-3-4-1-5.smt b/test/regress/regress1/xs-09-16-3-4-1-5.smt
new file mode 100644
index 000000000..549306c5b
--- /dev/null
+++ b/test/regress/regress1/xs-09-16-3-4-1-5.smt
@@ -0,0 +1,29 @@
+(benchmark mathsat
+:source { MathSat group }
+:logic QF_UFLIA
+:status unsat
+:category { industrial }
+:difficulty { 2 }
+:extrafuns ((fmt1 Int))
+:extrafuns ((fmt0 Int))
+:extrafuns ((arg1 Int))
+:extrafuns ((arg0 Int))
+:extrafuns ((fmt_length Int))
+:extrafuns ((distance Int))
+:extrafuns ((adr_hi Int))
+:extrafuns ((adr_medhi Int))
+:extrafuns ((adr_medlo Int))
+:extrafuns ((adr_lo Int))
+:extrafuns ((select_format Int Int))
+:extrafuns ((percent Int))
+:extrafuns ((s Int))
+:extrafuns ((s_count Int Int))
+:extrafuns ((x Int))
+:extrafuns ((x_count Int Int))
+:formula
+(flet ($concval (and (and (and (and (and (and (and (and (= distance 16) (= fmt_length 9)) (= adr_lo 3)) (= adr_medlo 4)) (= adr_medhi 1)) (= adr_hi 5)) (= percent 37)) (= s 115)) (= x 120)))
+(flet ($attack (and (and (and (and (and (and (and (= fmt0 0) (= arg0 (- fmt0 distance))) (>= arg1 fmt0)) (< fmt1 (- (+ fmt0 fmt_length) 1))) (> fmt1 (+ fmt0 1))) (>= arg1 (+ arg0 distance))) (< arg1 (- (+ (+ arg0 distance) fmt_length) 4))) (= arg1 (+ (+ arg0 (* 4 (s_count (- (- fmt1 2) fmt0)))) (* 4 (x_count (- (- fmt1 2) fmt0)))))))
+(flet ($restrict (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (or (= (select_format 0) percent) (= (select_format 0) s)) (= (select_format 0) x)) (= (select_format 0) adr_lo)) (= (select_format 0) adr_medlo)) (= (select_format 0) adr_medhi)) (= (select_format 0) adr_hi)) (= (select_format 0) 255)) (= (select_format 1) percent)) (= (select_format 1) s)) (= (select_format 1) x)) (= (select_format 1) adr_lo)) (= (select_format 1) adr_medlo)) (= (select_format 1) adr_medhi)) (= (select_format 1) adr_hi)) (= (select_format 1) 255)) (= (select_format 2) percent)) (= (select_format 2) s)) (= (select_format 2) x)) (= (select_format 2) adr_lo)) (= (select_format 2) adr_medlo)) (= (select_format 2) adr_medhi)) (= (select_format 2) adr_hi)) (= (select_format 2) 255)) (= (select_format 3) percent)) (= (select_format 3) s)) (= (select_format 3) x)) (= (select_format 3) adr_lo)) (= (select_format 3) adr_medlo)) (= (select_format 3) adr_medhi)) (= (select_format 3) adr_hi)) (= (select_format 3) 255)) (= (select_format 4) percent)) (= (select_format 4) s)) (= (select_format 4) x)) (= (select_format 4) adr_lo)) (= (select_format 4) adr_medlo)) (= (select_format 4) adr_medhi)) (= (select_format 4) adr_hi)) (= (select_format 4) 255)) (= (select_format 5) percent)) (= (select_format 5) s)) (= (select_format 5) x)) (= (select_format 5) adr_lo)) (= (select_format 5) adr_medlo)) (= (select_format 5) adr_medhi)) (= (select_format 5) adr_hi)) (= (select_format 5) 255)) (= (select_format 6) percent)) (= (select_format 6) s)) (= (select_format 6) x)) (= (select_format 6) adr_lo)) (= (select_format 6) adr_medlo)) (= (select_format 6) adr_medhi)) (= (select_format 6) adr_hi)) (= (select_format 6) 255)) (= (select_format 7) percent)) (= (select_format 7) s)) (= (select_format 7) x)) (= (select_format 7) adr_lo)) (= (select_format 7) adr_medlo)) (= (select_format 7) adr_medhi)) (= (select_format 7) adr_hi)) (= (select_format 7) 255)) (= (select_format 8) percent)) (= (select_format 8) s)) (= (select_format 8) x)) (= (select_format 8) adr_lo)) (= (select_format 8) adr_medlo)) (= (select_format 8) adr_medhi)) (= (select_format 8) adr_hi)) (= (select_format 8) 255)))
+(flet ($counterdef (and (and (and (and (and (and (and (and (and (and (and (and (and (and (and (and (and (if_then_else (and (= (select_format 0) percent) (= (select_format 1) s)) (= (s_count 0) 1) (= (s_count 0) 0)) (if_then_else (and (= (select_format 1) percent) (= (select_format 2) s)) (= (s_count 1) (+ (s_count 0) 1)) (= (s_count 1) (s_count 0)))) (if_then_else (and (= (select_format 2) percent) (= (select_format 3) s)) (= (s_count 2) (+ (s_count 1) 1)) (= (s_count 2) (s_count 1)))) (if_then_else (and (= (select_format 3) percent) (= (select_format 4) s)) (= (s_count 3) (+ (s_count 2) 1)) (= (s_count 3) (s_count 2)))) (if_then_else (and (= (select_format 4) percent) (= (select_format 5) s)) (= (s_count 4) (+ (s_count 3) 1)) (= (s_count 4) (s_count 3)))) (if_then_else (and (= (select_format 5) percent) (= (select_format 6) s)) (= (s_count 5) (+ (s_count 4) 1)) (= (s_count 5) (s_count 4)))) (if_then_else (and (= (select_format 6) percent) (= (select_format 7) s)) (= (s_count 6) (+ (s_count 5) 1)) (= (s_count 6) (s_count 5)))) (if_then_else (and (= (select_format 7) percent) (= (select_format 8) s)) (= (s_count 7) (+ (s_count 6) 1)) (= (s_count 7) (s_count 6)))) (if_then_else (and (= (select_format 8) percent) (= (select_format 9) s)) (= (s_count 8) (+ (s_count 7) 1)) (= (s_count 8) (s_count 7)))) (if_then_else (and (= (select_format 0) percent) (= (select_format 1) x)) (= (x_count 0) 1) (= (x_count 0) 0))) (if_then_else (and (= (select_format 1) percent) (= (select_format 2) x)) (= (x_count 1) (+ (x_count 0) 1)) (= (x_count 1) (x_count 0)))) (if_then_else (and (= (select_format 2) percent) (= (select_format 3) x)) (= (x_count 2) (+ (x_count 1) 1)) (= (x_count 2) (x_count 1)))) (if_then_else (and (= (select_format 3) percent) (= (select_format 4) x)) (= (x_count 3) (+ (x_count 2) 1)) (= (x_count 3) (x_count 2)))) (if_then_else (and (= (select_format 4) percent) (= (select_format 5) x)) (= (x_count 4) (+ (x_count 3) 1)) (= (x_count 4) (x_count 3)))) (if_then_else (and (= (select_format 5) percent) (= (select_format 6) x)) (= (x_count 5) (+ (x_count 4) 1)) (= (x_count 5) (x_count 4)))) (if_then_else (and (= (select_format 6) percent) (= (select_format 7) x)) (= (x_count 6) (+ (x_count 5) 1)) (= (x_count 6) (x_count 5)))) (if_then_else (and (= (select_format 7) percent) (= (select_format 8) x)) (= (x_count 7) (+ (x_count 6) 1)) (= (x_count 7) (x_count 6)))) (if_then_else (and (= (select_format 8) percent) (= (select_format 9) x)) (= (x_count 8) (+ (x_count 7) 1)) (= (x_count 8) (x_count 7)))))
+(flet ($integral (and (or (or (or (or (or (or (or (or (= fmt1 (+ fmt0 0)) (= fmt1 (+ fmt0 1))) (= fmt1 (+ fmt0 2))) (= fmt1 (+ fmt0 3))) (= fmt1 (+ fmt0 4))) (= fmt1 (+ fmt0 5))) (= fmt1 (+ fmt0 6))) (= fmt1 (+ fmt0 7))) (= fmt1 (+ fmt0 8))) (or (or (or (or (or (= arg1 (+ fmt0 0)) (= arg1 (+ fmt0 1))) (= arg1 (+ fmt0 2))) (= arg1 (+ fmt0 3))) (= arg1 (+ fmt0 4))) (= arg1 (+ fmt0 5)))))
+(and (and (and (and (and $concval $attack) $restrict) $counterdef) $integral) (not (and (and (and (and (and (= (select_format fmt1) percent) (= (select_format (+ fmt1 1)) s)) (= (select_format arg1) adr_lo)) (= (select_format (+ arg1 1)) adr_medlo)) (= (select_format (+ arg1 2)) adr_medhi)) (= (select_format (+ arg1 3)) adr_hi))))))))))
diff --git a/test/regress/regress2/Makefile.am b/test/regress/regress2/Makefile.am
index e0524b694..e4e5d8d29 100644
--- a/test/regress/regress2/Makefile.am
+++ b/test/regress/regress2/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
@@ -23,9 +27,14 @@ TESTS = bmc-ibm-1.smt \
friedman_n6_i4.smt \
hole9.cvc \
qwh.35.405.shuffled-as.sat03-1651.smt \
- eq_diamond14.smt
-
-EXTRA_DIST = $(TESTS)
+ eq_diamond14.smt \
+ incorrect1.smt \
+ incorrect2.smt \
+ bug497.cvc \
+ pp-regfile.smt
+
+EXTRA_DIST = $(TESTS) \
+ pp-regfile.smt.expect
#if CVC4_BUILD_PROFILE_COMPETITION
#else
diff --git a/test/regress/regress0/bug497.cvc b/test/regress/regress2/bug497.cvc
index ce34ab6ad..ce34ab6ad 100644
--- a/test/regress/regress0/bug497.cvc
+++ b/test/regress/regress2/bug497.cvc
diff --git a/test/regress/regress0/uflra/incorrect1.smt b/test/regress/regress2/incorrect1.smt
index 23425d462..23425d462 100644
--- a/test/regress/regress0/uflra/incorrect1.smt
+++ b/test/regress/regress2/incorrect1.smt
diff --git a/test/regress/regress0/uflra/incorrect2.smt b/test/regress/regress2/incorrect2.smt
index 23425d462..23425d462 100644
--- a/test/regress/regress0/uflra/incorrect2.smt
+++ b/test/regress/regress2/incorrect2.smt
diff --git a/test/regress/regress0/decision/pp-regfile.smt b/test/regress/regress2/pp-regfile.smt
index e60be055a..e60be055a 100644
--- a/test/regress/regress0/decision/pp-regfile.smt
+++ b/test/regress/regress2/pp-regfile.smt
diff --git a/test/regress/regress2/pp-regfile.smt.expect b/test/regress/regress2/pp-regfile.smt.expect
new file mode 100644
index 000000000..b862d0b39
--- /dev/null
+++ b/test/regress/regress2/pp-regfile.smt.expect
@@ -0,0 +1,3 @@
+% COMMAND-LINE: --decision=justification
+% EXPECT: unsat
+% EXIT: 20
diff --git a/test/regress/regress3/Makefile.am b/test/regress/regress3/Makefile.am
index ed3e66b20..213157491 100644
--- a/test/regress/regress3/Makefile.am
+++ b/test/regress/regress3/Makefile.am
@@ -1,6 +1,10 @@
SUBDIRS = .
-BINARY = cvc4
+# don't override a BINARY imported from a personal.mk
+@mk_if@eq ($(BINARY),)
+@mk_empty@BINARY = cvc4
+end@mk_if@
+
LOG_COMPILER = @srcdir@/../run_regression
AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
diff --git a/test/regress/run_regression b/test/regress/run_regression
index 084df6ac9..e9c17a3af 100755
--- a/test/regress/run_regression
+++ b/test/regress/run_regression
@@ -164,21 +164,35 @@ elif expr "$benchmark" : '.*\.cvc$' &>/dev/null; then
fi
command_line=`grep '^% COMMAND-LINE: ' "$benchmark" | sed 's,^% COMMAND-LINE: ,,'`
elif expr "$benchmark" : '.*\.p$' &>/dev/null; then
- proof_command=PROOFS-NOT-SUPPORTED-IN-SMTLIB-V1;
+ proof_command=PROOFS-NOT-SUPPORTED-IN-TPTP;
lang=tptp
+ command_line=--finite-model-find
expected_proof=`grep '^% PROOF' "$benchmark" &>/dev/null && echo yes`
expected_output=$(grep '^% EXPECT: ' "$benchmark")
expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark" | sed 's,^% EXPECT-ERROR: ,,'`
if [ -z "$expected_output" -a -z "$expected_error" ]; then
- error "cannot determine expected output of \`$benchmark': " \
- "please use \`% EXPECT:' and/or \`% EXPECT-ERROR:' gestures"
+ if grep -q '^% Status *: ' "$benchmark"; then
+ expected_output="$(grep '^% *Status *: ' "$benchmark" | head -1 | awk '{print$NF}')"
+ case "$expected_output" in
+ Theorem|Unsatisfiable) expected_exit_status=20 ;;
+ CounterSatisfiable|Satisfiable) expected_exit_status=10 ;;
+ GaveUp) expected_exit_status=0 ;;
+ esac
+ expected_output="% SZS status $expected_output for $(basename "$benchmark" | sed 's,\.p$,,')"
+ else
+ error "cannot determine expected output of \`$benchmark': " \
+ "please use \`% EXPECT:' and/or \`% EXPECT-ERROR:' gestures"
+ fi
+ else
+ expected_output=$(echo "$expected_output" | perl -pe 's,^% EXPECT: ,,;s,\r,,')
+ expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
fi
- expected_output=$(echo "$expected_output" | perl -pe 's,^% EXPECT: ,,;s,\r,,')
- expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
if [ -z "$expected_exit_status" ]; then
error "cannot determine expected exit status of \`$benchmark': please use \`% EXIT:' gesture"
fi
- command_line=`grep '^% COMMAND-LINE: ' "$benchmark" | sed 's,^% COMMAND-LINE: ,,'`
+ if grep -q '^% COMMAND-LINE: ' "$benchmark"; then
+ command_line=`grep '^% COMMAND-LINE: ' "$benchmark" | sed 's,^% COMMAND-LINE: ,,'`
+ fi
else
error "benchmark \`$benchmark' must be *.cvc or *.smt or *.smt2 or *.p"
fi
@@ -199,7 +213,7 @@ else
echo "$expected_output" >"$expoutfile"
fi
check_models=false
-if grep '^sat$' "$expoutfile" &>/dev/null || grep '^invalid$' "$expoutfile" &>/dev/null; then
+if grep '^sat$' "$expoutfile" &>/dev/null || grep '^invalid$' "$expoutfile" &>/dev/null || grep '^unknown$' "$expoptfile" &>/dev/null; then
if ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--check-models' &>/dev/null &&
! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--no-check-models' &>/dev/null; then
# later on, we'll run another test with --check-models on
@@ -223,16 +237,18 @@ cvc4base=`basename "$cvc4"`
cvc4full="$cvc4dirfull/$cvc4base"
if [ $dump = no ]; then
echo running $wrapper $cvc4full $CVC4_REGRESSION_ARGS $command_line --segv-nospin `basename "$benchmark"` [from working dir `dirname "$benchmark"`]
+ time ( :; \
( cd `dirname "$benchmark"`;
$wrapper "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --segv-nospin `basename "$benchmark"`;
echo $? >"$exitstatusfile"
- ) > "$outfile" 2> "$errfile"
+ ) > "$outfile" 2> "$errfile" )
else
echo running $wrapper $cvc4full $CVC4_REGRESSION_ARGS $command_line --preprocess-only --dump=clauses --output-lang=smt2 -q --segv-nospin `basename "$benchmark"` \| $wrapper $cvc4full $CVC4_REGRESSION_ARGS $command_line --lang=smt2 - [from working dir `dirname "$benchmark"`]
+ time ( :; \
( cd `dirname "$benchmark"`;
$wrapper "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --preprocess-only --dump=clauses --output-lang=smt2 -q --segv-nospin `basename "$benchmark"` | $wrapper "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --lang=smt2 -;
echo $? >"$exitstatusfile"
- ) > "$outfile" 2> "$errfile"
+ ) > "$outfile" 2> "$errfile" )
fi
diffs=`diff -u --strip-trailing-cr "$expoutfile" "$outfile"`
@@ -263,10 +279,11 @@ if [ "$proof" = yes -a "$expected_proof" = yes ]; then
cp "$benchmark" "$pfbenchmark";
echo "$proof_command" >>"$pfbenchmark";
echo running $wrapper $cvc4full $CVC4_REGRESSION_ARGS $command_line --proof --segv-nospin `basename "$pfbenchmark"` [from working dir `dirname "$pfbenchmark"`]
+ time ( :; \
( cd `dirname "$pfbenchmark"`;
$wrapper "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --proof --segv-nospin `basename "$pfbenchmark"`;
echo $? >"$exitstatusfile"
- ) > "$outfile" 2> "$errfile"
+ ) > "$outfile" 2> "$errfile" )
gettemp pfoutfile cvc4_proof.$$.XXXXXXXXXX
diff --unchanged-group-format='' \
diff --git a/test/system/Makefile.am b/test/system/Makefile.am
index d79fcb7ba..90867abc9 100644
--- a/test/system/Makefile.am
+++ b/test/system/Makefile.am
@@ -43,8 +43,8 @@ TEST_DEPS_NODIST = \
if CVC4_BUILD_LIBCOMPAT
TEST_DEPS_NODIST += \
- $(abs_top_builddir)/src/compat/libcvc4compat.la \
- cvc3_george.lo
+ $(abs_top_builddir)/src/compat/libcvc4compat.la
+# cvc3_george.lo
endif
TEST_DEPS = \
@@ -89,9 +89,6 @@ $(filter-out %.class.lo,$(TESTS:%=%.lo)): %.lo: %.cpp
$(AM_V_CXX)$(LTCXXCOMPILE) $(AM_CXXFLAGS) -c -o $@ $+
$(filter-out %.class,$(TESTS)): %: %.lo $(LIBADD)
$(AM_V_CXXLD)$(system_LINK) $(LIBADD) $(AM_LDFLAGS) $(LIBS) $<
-#cvc3_main: cvc3_george.lo $(LIBADD)
-cvc3_main: $(LIBADD)
- $(AM_V_CXXLD)$(system_LINK) $(LIBADD) $(AM_LDFLAGS) $(LIBS) $+
CVC4JavaTest.class: CVC4JavaTest.java @abs_top_builddir@/src/bindings/CVC4.jar @abs_top_builddir@/src/bindings/java/libcvc4jni.la
$(AM_V_JAVAC)$(JAVAC) -classpath @abs_top_builddir@/src/bindings/CVC4.jar -d $(builddir) $<
diff --git a/test/unit/expr/attribute_white.h b/test/unit/expr/attribute_white.h
index 11a3d85c8..5ce5badd0 100644
--- a/test/unit/expr/attribute_white.h
+++ b/test/unit/expr/attribute_white.h
@@ -94,7 +94,7 @@ public:
// and that the next ID to be assigned is strictly greater than
// those that have already been assigned.
- unsigned lastId = attr::LastAttributeId<string, false>::s_id;
+ unsigned lastId = attr::LastAttributeId<string, false>::getId();
TS_ASSERT_LESS_THAN(VarNameAttr::s_id, lastId);
TS_ASSERT_LESS_THAN(TestStringAttr1::s_id, lastId);
TS_ASSERT_LESS_THAN(TestStringAttr2::s_id, lastId);
@@ -103,10 +103,10 @@ public:
TS_ASSERT_DIFFERS(VarNameAttr::s_id, TestStringAttr2::s_id);
TS_ASSERT_DIFFERS(TestStringAttr1::s_id, TestStringAttr2::s_id);
- //lastId = attr::LastAttributeId<void*, false>::s_id;
+ //lastId = attr::LastAttributeId<void*, false>::getId();
//TS_ASSERT_LESS_THAN(theory::uf::ECAttr::s_id, lastId);
- lastId = attr::LastAttributeId<bool, false>::s_id;
+ lastId = attr::LastAttributeId<bool, false>::getId();
TS_ASSERT_LESS_THAN(TestFlag1::s_id, lastId);
TS_ASSERT_LESS_THAN(TestFlag2::s_id, lastId);
TS_ASSERT_LESS_THAN(TestFlag3::s_id, lastId);
@@ -123,14 +123,14 @@ public:
TS_ASSERT_DIFFERS(TestFlag3::s_id, TestFlag5::s_id);
TS_ASSERT_DIFFERS(TestFlag4::s_id, TestFlag5::s_id);
- lastId = attr::LastAttributeId<bool, true>::s_id;
+ lastId = attr::LastAttributeId<bool, true>::getId();
TS_ASSERT_LESS_THAN(TestFlag1cd::s_id, lastId);
TS_ASSERT_LESS_THAN(TestFlag2cd::s_id, lastId);
TS_ASSERT_DIFFERS(TestFlag1cd::s_id, TestFlag2cd::s_id);
cout << "1: " << TestFlag1cd::s_id << endl;
cout << "2: " << TestFlag2cd::s_id << endl;
- lastId = attr::LastAttributeId<Node, false>::s_id;
+ lastId = attr::LastAttributeId<Node, false>::getId();
// TS_ASSERT_LESS_THAN(theory::PreRewriteCache::s_id, lastId);
// TS_ASSERT_LESS_THAN(theory::PostRewriteCache::s_id, lastId);
// TS_ASSERT_LESS_THAN(theory::PreRewriteCacheTop::s_id, lastId);
@@ -142,7 +142,7 @@ public:
// TS_ASSERT_DIFFERS(theory::PostRewriteCache::s_id, theory::PostRewriteCacheTop::s_id);
// TS_ASSERT_DIFFERS(theory::PreRewriteCacheTop::s_id, theory::PostRewriteCacheTop::s_id);
- lastId = attr::LastAttributeId<TypeNode, false>::s_id;
+ lastId = attr::LastAttributeId<TypeNode, false>::getId();
TS_ASSERT_LESS_THAN(NodeManager::TypeAttr::s_id, lastId);
}
diff --git a/test/unit/expr/expr_public.h b/test/unit/expr/expr_public.h
index c66b5cb1f..7f6385d36 100644
--- a/test/unit/expr/expr_public.h
+++ b/test/unit/expr/expr_public.h
@@ -342,7 +342,7 @@ public:
void testIsConst() {
/* bool isConst() const; */
- Debug.on("isConst");
+ //Debug.on("isConst");
TS_ASSERT(!a_bool->isConst());
TS_ASSERT(!b_bool->isConst());
diff --git a/test/unit/expr/type_cardinality_public.h b/test/unit/expr/type_cardinality_public.h
index 2441b7b0d..3c2609e3e 100644
--- a/test/unit/expr/type_cardinality_public.h
+++ b/test/unit/expr/type_cardinality_public.h
@@ -200,7 +200,7 @@ public:
}
void testBitvectors() {
- Debug.on("bvcard");
+ //Debug.on("bvcard");
TS_ASSERT( d_em->mkBitVectorType(0).getCardinality().compare(0) == Cardinality::EQUAL );
Cardinality lastCard = 0;
for(unsigned i = 1; i <= 65; ++i) {
diff --git a/test/unit/parser/parser_black.h b/test/unit/parser/parser_black.h
index 1dbaf7cdf..8ff62c25a 100644
--- a/test/unit/parser/parser_black.h
+++ b/test/unit/parser/parser_black.h
@@ -395,7 +395,7 @@ public:
#ifndef CVC4_COMPETITION_MODE
tryBadInput("(assert)"); // no args
tryBadInput("(set-info :notes |Symbols can't contain the | character|)");
- tryBadInput("(set-logic QF_UF) (check-sat true)"); // shouldn't have an arg
+ tryBadInput("(set-logic QF_UF) (check-sat true)", true); // check-sat shouldn't have an arg
tryBadInput("(declare-sort a)"); // no arg
tryBadInput("(declare-sort a 0) (declare-sort a 0)"); // double decl
tryBadInput("(set-logic QF_UF) (declare-fun p Bool)"); // should be "p () Bool"
diff --git a/test/unit/theory/logic_info_white.h b/test/unit/theory/logic_info_white.h
index a0d415296..8f9417966 100644
--- a/test/unit/theory/logic_info_white.h
+++ b/test/unit/theory/logic_info_white.h
@@ -511,6 +511,7 @@ public:
info = info.getUnlockedCopy();
TS_ASSERT( !info.isLocked() );
+ info.disableTheory(THEORY_STRINGS);
info.arithOnlyLinear();
info.disableIntegers();
info.lock();
@@ -555,10 +556,10 @@ public:
TS_ASSERT( !info.isTheoryEnabled( THEORY_BV ) );
TS_ASSERT( !info.isTheoryEnabled( THEORY_DATATYPES ) );
TS_ASSERT( info.isTheoryEnabled( THEORY_BOOL ) );
- TS_ASSERT( !info.isLinear() );
- TS_ASSERT( !info.areIntegersUsed() );
- TS_ASSERT( !info.isDifferenceLogic() );
- TS_ASSERT( !info.areRealsUsed() );
+ TS_ASSERT_THROWS( info.isLinear(), IllegalArgumentException );
+ TS_ASSERT_THROWS( info.areIntegersUsed(), IllegalArgumentException );
+ TS_ASSERT_THROWS( info.isDifferenceLogic(), IllegalArgumentException );
+ TS_ASSERT_THROWS( info.areRealsUsed(), IllegalArgumentException );
// check copy is unchanged
info = info.getUnlockedCopy();
@@ -574,10 +575,10 @@ public:
TS_ASSERT( !info.isTheoryEnabled( THEORY_BV ) );
TS_ASSERT( !info.isTheoryEnabled( THEORY_DATATYPES ) );
TS_ASSERT( info.isTheoryEnabled( THEORY_BOOL ) );
- TS_ASSERT( !info.isLinear() );
- TS_ASSERT( !info.areIntegersUsed() );
- TS_ASSERT( !info.isDifferenceLogic() );
- TS_ASSERT( !info.areRealsUsed() );
+ TS_ASSERT_THROWS( info.isLinear(), IllegalArgumentException );
+ TS_ASSERT_THROWS( info.areIntegersUsed(), IllegalArgumentException );
+ TS_ASSERT_THROWS( info.isDifferenceLogic(), IllegalArgumentException );
+ TS_ASSERT_THROWS( info.areRealsUsed(), IllegalArgumentException );
// check all-included logic
info = info.getUnlockedCopy();
diff --git a/test/unit/theory/theory_arith_white.h b/test/unit/theory/theory_arith_white.h
index 844fb57d1..3247b8c73 100644
--- a/test/unit/theory/theory_arith_white.h
+++ b/test/unit/theory/theory_arith_white.h
@@ -60,6 +60,7 @@ class TheoryArithWhite : public CxxTest::TestSuite {
TypeNode* d_booleanType;
TypeNode* d_realType;
+ TypeNode* d_intType;
const Rational d_zero;
const Rational d_one;
@@ -120,10 +121,12 @@ public:
d_booleanType = new TypeNode(d_nm->booleanType());
d_realType = new TypeNode(d_nm->realType());
+ d_intType = new TypeNode(d_nm->integerType());
}
void tearDown() {
+ delete d_intType;
delete d_realType;
delete d_booleanType;
@@ -281,4 +284,37 @@ public:
TS_ASSERT_EQUALS(d_outputChannel.getIthCallType(1), LEMMA);
TS_ASSERT_EQUALS(d_outputChannel.getIthNode(1), geq0OrLeq1);
}
+
+ void testIntNormalForm() {
+ Node x = d_nm->mkVar(*d_intType);
+ Node c0 = d_nm->mkConst<Rational>(d_zero);
+ Node c1 = d_nm->mkConst<Rational>(d_one);
+ Node c2 = d_nm->mkConst<Rational>(Rational(2));
+
+
+ Node geq0 = d_nm->mkNode(GEQ, x, c0);
+ Node geq1 = d_nm->mkNode(GEQ, x, c1);
+ Node geq2 = d_nm->mkNode(GEQ, x, c2);
+
+ TS_ASSERT_EQUALS(Rewriter::rewrite(geq0), geq0);
+ TS_ASSERT_EQUALS(Rewriter::rewrite(geq1), geq1);
+
+ Node gt0 = d_nm->mkNode(GT, x, c0);
+ Node gt1 = d_nm->mkNode(GT, x, c1);
+
+ TS_ASSERT_EQUALS(Rewriter::rewrite(gt0), Rewriter::rewrite(geq1));
+ TS_ASSERT_EQUALS(Rewriter::rewrite(gt1), Rewriter::rewrite(geq2));
+
+ Node lt0 = d_nm->mkNode(LT, x, c0);
+ Node lt1 = d_nm->mkNode(LT, x, c1);
+
+ TS_ASSERT_EQUALS(Rewriter::rewrite(lt0), Rewriter::rewrite(geq0.notNode()));
+ TS_ASSERT_EQUALS(Rewriter::rewrite(lt1), Rewriter::rewrite(geq1.notNode()));
+
+ Node leq0 = d_nm->mkNode(LEQ, x, c0);
+ Node leq1 = d_nm->mkNode(LEQ, x, c1);
+
+ TS_ASSERT_EQUALS(Rewriter::rewrite(leq0), Rewriter::rewrite(geq1.notNode()));
+ TS_ASSERT_EQUALS(Rewriter::rewrite(leq1), Rewriter::rewrite(geq2.notNode()));
+ }
};
diff --git a/test/unit/theory/theory_engine_white.h b/test/unit/theory/theory_engine_white.h
index c9bea1795..4035b85da 100644
--- a/test/unit/theory/theory_engine_white.h
+++ b/test/unit/theory/theory_engine_white.h
@@ -76,6 +76,9 @@ class FakeOutputChannel : public OutputChannel {
void handleUserAttribute( const char* attr, Theory* t ){
Unimplemented();
}
+ LemmaStatus splitLemma(TNode n, bool removable) throw(TypeCheckingExceptionPrivate, AssertionException){
+ Unimplemented();
+ }
};/* class FakeOutputChannel */
template<TheoryId theory>
diff --git a/test/unit/theory/theory_white.h b/test/unit/theory/theory_white.h
index 126f57060..d9df2912b 100644
--- a/test/unit/theory/theory_white.h
+++ b/test/unit/theory/theory_white.h
@@ -76,6 +76,11 @@ public:
return LemmaStatus(Node::null(), 0);
}
+ LemmaStatus splitLemma(TNode n, bool removable) throw (TypeCheckingExceptionPrivate, AssertionException){
+ push(LEMMA, n);
+ return LemmaStatus(Node::null(), 0);
+ }
+
void requirePhase(TNode, bool)
throw(Interrupted, AssertionException) {
Unreachable();
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback